Skip to content

Commit d3f3288

Browse files
authored
Delete per-container handling of for range loops (#547)
1 parent 937c2cc commit d3f3288

62 files changed

Lines changed: 645 additions & 749 deletions

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: 20 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1372,6 +1372,9 @@ bool Converter::VisitDeclStmt(clang::DeclStmt *stmt) {
13721372
hoisted_records_ += std::move(buf).str();
13731373
continue;
13741374
}
1375+
if (var && IsAliasOfInit(ctx_, var)) {
1376+
continue;
1377+
}
13751378
if (var && var->isImplicit()) {
13761379
VisitVarDecl(var);
13771380
} else {
@@ -1487,112 +1490,25 @@ bool Converter::VisitForStmt(clang::ForStmt *stmt) {
14871490
return false;
14881491
}
14891492

1490-
void Converter::ConvertLoopVariable(clang::VarDecl *decl,
1491-
clang::Expr *range_init) {
1492-
auto loop_var_type = decl->getType();
1493-
auto loop_var_name = GetNamedDeclAsString(decl);
1494-
1495-
if (loop_var_type->isReferenceType()) {
1496-
auto pointee_type = loop_var_type->getPointeeType();
1497-
Convert(range_init);
1498-
if (pointee_type.isConstQualified()) {
1499-
StrCat(std::format(".as_ptr().add({})", loop_var_name));
1500-
} else {
1501-
StrCat(std::format(".as_mut_ptr().add({})", loop_var_name));
1502-
}
1503-
} else {
1504-
{
1505-
PushExplicitAutoref autoref(*this, /*is_mut=*/false);
1506-
Convert(range_init);
1507-
}
1508-
StrCat(std::format("[{}]", loop_var_name));
1509-
StrCat(".clone()");
1510-
}
1511-
}
1512-
1513-
void Converter::ConvertForRangeBody(clang::CXXForRangeStmt *stmt) {
1514-
PushBreakTarget push(break_target_, BreakTarget::Loop);
1515-
curr_for_inc_.emplace_back(nullptr);
1516-
ConvertBodyStmts(stmt->getBody());
1517-
curr_for_inc_.pop_back();
1518-
}
1519-
15201493
bool Converter::VisitCXXForRangeStmt(clang::CXXForRangeStmt *stmt) {
1521-
auto range_init_type = stmt->getRangeInit()->getType();
1522-
1523-
if (!Mapper::Contains(ctx_, range_init_type.getUnqualifiedType())) {
1524-
// FIXME: improve error handling
1525-
log() << "for range stmts only for types in std namespace\n";
1526-
}
1527-
1528-
log() << "GetClassName: " << GetClassName(range_init_type) << '\n';
1529-
1530-
if (GetClassName(range_init_type) == "std::map") {
1531-
return VisitCXXForRangeStmtMap(stmt);
1532-
}
1533-
if (GetClassName(range_init_type) == "std::basic_string") {
1534-
return VisitCXXForRangeStmtString(stmt);
1535-
}
1536-
return VisitCXXForRangeStmtVector(stmt);
1537-
}
1538-
1539-
bool Converter::VisitCXXForRangeStmtMap(clang::CXXForRangeStmt *stmt) {
1540-
auto begin =
1541-
llvm::cast<clang::VarDecl>(stmt->getBeginStmt()->getSingleDecl());
1542-
1494+
PushBreakTarget push(break_target_, BreakTarget::Loop);
1495+
Convert(stmt->getInit());
1496+
Convert(stmt->getRangeStmt());
1497+
auto *begin =
1498+
clang::cast<clang::VarDecl>(stmt->getBeginStmt()->getSingleDecl());
1499+
auto *end = clang::cast<clang::VarDecl>(stmt->getEndStmt()->getSingleDecl());
1500+
begin->setDeclName(stmt->getLoopVariable()->getDeclName());
15431501
StrCat("'loop_:");
1544-
auto map_type = Mapper::Map(*this, stmt->getRangeInit()->getType());
15451502
StrCat(keyword::kFor, GetNamedDeclAsString(begin), keyword::kIn,
1546-
"UnsafeMap::range(&");
1547-
Convert(stmt->getRangeInit());
1548-
StrCat(std::format(" as *const {})", map_type));
1503+
"IterRange::new(", ConvertFreshRValue(begin->getInit()), token::kComma,
1504+
ConvertFreshRValue(end->getInit()), ')');
15491505
{
15501506
PushBrace brace(*this);
1507+
curr_for_inc_.emplace_back(nullptr);
15511508
Convert(stmt->getLoopVarStmt());
1552-
ConvertForRangeBody(stmt);
1553-
}
1554-
1555-
return false;
1556-
}
1557-
1558-
bool Converter::VisitCXXForRangeStmtString(clang::CXXForRangeStmt *stmt) {
1559-
return VisitCXXForRangeStmtIndexBased(stmt, "len()-1");
1560-
}
1561-
1562-
bool Converter::VisitCXXForRangeStmtVector(clang::CXXForRangeStmt *stmt) {
1563-
return VisitCXXForRangeStmtIndexBased(stmt, "len()");
1564-
}
1565-
1566-
bool Converter::VisitCXXForRangeStmtIndexBased(clang::CXXForRangeStmt *stmt,
1567-
const char *len_suffix) {
1568-
auto *loop_var = stmt->getLoopVariable();
1569-
auto loop_var_name = GetNamedDeclAsString(loop_var);
1570-
1571-
StrCat("'loop_:");
1572-
StrCat(keyword::kFor, loop_var_name, keyword::kIn, "0..");
1573-
{
1574-
PushParen range(*this);
1575-
Convert(stmt->getRangeInit());
1576-
StrCat(token::kDot, len_suffix);
1577-
}
1578-
{
1579-
PushBrace body(*this);
1580-
StrCat(keyword::kLet);
1581-
1582-
auto loop_var_type = loop_var->getType();
1583-
if (!loop_var_type.isConstQualified()) {
1584-
StrCat(keyword_mut_);
1585-
}
1586-
1587-
StrCat(loop_var_name);
1588-
StrCat(token::kAssign);
1589-
1590-
ConvertLoopVariable(loop_var, stmt->getRangeInit());
1591-
1592-
StrCat(token::kSemiColon);
1593-
ConvertForRangeBody(stmt);
1509+
ConvertBodyStmts(stmt->getBody());
1510+
curr_for_inc_.pop_back();
15941511
}
1595-
15961512
return false;
15971513
}
15981514

@@ -3268,6 +3184,11 @@ bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) {
32683184
Convert(init);
32693185
return false;
32703186
}
3187+
if (auto var = clang::dyn_cast<clang::VarDecl>(expr->getDecl());
3188+
var && IsAliasOfInit(ctx_, var)) {
3189+
Convert(var->getInit());
3190+
return false;
3191+
}
32713192
ConvertDeclRefValue(expr, expr->getDecl());
32723193
return false;
32733194
}

‎cpp2rust/converter/converter.h‎

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -223,17 +223,6 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
223223

224224
virtual bool VisitCXXForRangeStmt(clang::CXXForRangeStmt *stmt);
225225

226-
virtual bool VisitCXXForRangeStmtMap(clang::CXXForRangeStmt *stmt);
227-
228-
virtual bool VisitCXXForRangeStmtVector(clang::CXXForRangeStmt *stmt);
229-
230-
virtual bool VisitCXXForRangeStmtString(clang::CXXForRangeStmt *stmt);
231-
232-
bool VisitCXXForRangeStmtIndexBased(clang::CXXForRangeStmt *stmt,
233-
const char *len_suffix);
234-
235-
void ConvertForRangeBody(clang::CXXForRangeStmt *stmt);
236-
237226
virtual bool VisitBreakStmt(clang::BreakStmt *stmt);
238227

239228
virtual bool VisitContinueStmt(clang::ContinueStmt *stmt);
@@ -750,9 +739,6 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
750739
virtual void ConvertCast(clang::QualType qual_type,
751740
int line = __builtin_LINE());
752741

753-
virtual void ConvertLoopVariable(clang::VarDecl *decl,
754-
clang::Expr *range_init);
755-
756742
virtual bool ConvertCXXOperatorCallExpr(clang::CXXOperatorCallExpr *expr);
757743

758744
std::string GetMappedAsString(clang::Expr *expr, clang::Expr **args = nullptr,

‎cpp2rust/converter/converter_lib.cpp‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1920,10 +1920,10 @@ std::optional<clang::QualType> GetParamImplicitConvertTarget(clang::Expr *expr,
19201920
return fn->getParamDecl(param_idx)->getType().getNonReferenceType();
19211921
}
19221922

1923-
std::string GetClassName(clang::QualType type) {
1924-
if (auto *record = type->getAsCXXRecordDecl())
1925-
return record->getQualifiedNameAsString();
1926-
return {};
1923+
bool IsAliasOfInit(clang::ASTContext &ctx, const clang::VarDecl *var) {
1924+
auto *init = var->getInit();
1925+
return var->isImplicit() && var->getType()->isReferenceType() && init &&
1926+
init->isGLValue() && !init->HasSideEffects(ctx);
19271927
}
19281928

19291929
bool IsVaListType(clang::QualType type) {

‎cpp2rust/converter/converter_lib.h‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,10 +321,10 @@ clang::Expr *BuildInitExpr(clang::Sema &sema, clang::QualType type,
321321
llvm::ArrayRef<clang::Expr *> args,
322322
clang::SourceLocation loc);
323323

324-
std::string GetClassName(clang::QualType type);
325-
326324
bool IsVaListType(clang::QualType type);
327325

326+
bool IsAliasOfInit(clang::ASTContext &ctx, const clang::VarDecl *var);
327+
328328
bool NeedsImplicitScalarCast(clang::ASTContext &ctx, clang::QualType from,
329329
clang::QualType to);
330330

‎cpp2rust/converter/models/boxed_vars.cpp‎

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,17 @@ class AddressTakenVisitor
9595
: public clang::RecursiveASTVisitor<AddressTakenVisitor> {
9696
public:
9797
AddressTakenVisitor(clang::ASTContext &ctx,
98-
std::unordered_set<const clang::VarDecl *> &vars)
99-
: ctx_(ctx), address_taken_(vars) {}
98+
std::unordered_set<const clang::VarDecl *> &vars,
99+
std::unordered_set<const clang::VarDecl *> &iterators)
100+
: ctx_(ctx), address_taken_(vars), range_iterators_(iterators) {}
101+
102+
bool VisitCXXForRangeStmt(clang::CXXForRangeStmt *stmt) {
103+
if (auto *begin = stmt->getBeginStmt()) {
104+
range_iterators_.insert(
105+
clang::cast<clang::VarDecl>(begin->getSingleDecl()));
106+
}
107+
return true;
108+
}
100109

101110
bool shouldVisitTemplateInstantiations() const { return true; }
102111

@@ -249,18 +258,20 @@ class AddressTakenVisitor
249258

250259
clang::ASTContext &ctx_;
251260
std::unordered_set<const clang::VarDecl *> &address_taken_;
261+
std::unordered_set<const clang::VarDecl *> &range_iterators_;
252262
// The references to variables that only access their value.
253263
std::unordered_set<const clang::DeclRefExpr *> value_uses_;
254264
};
255265
} // namespace
256266

257267
BoxedVars::BoxedVars(clang::ASTContext &ctx) : ctx_(ctx) {
258-
AddressTakenVisitor(ctx, address_taken_)
268+
AddressTakenVisitor(ctx, address_taken_, range_iterators_)
259269
.TraverseDecl(ctx.getTranslationUnitDecl());
260270
}
261271

262272
bool BoxedVars::contains(const clang::VarDecl *decl) const {
263-
return !CanUnbox(ctx_, decl) || address_taken_.contains(decl);
273+
return !range_iterators_.contains(decl) &&
274+
(!CanUnbox(ctx_, decl) || address_taken_.contains(decl));
264275
}
265276

266277
namespace {

‎cpp2rust/converter/models/boxed_vars.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class BoxedVars {
2828
private:
2929
clang::ASTContext &ctx_;
3030
std::unordered_set<const clang::VarDecl *> address_taken_;
31+
std::unordered_set<const clang::VarDecl *> range_iterators_;
3132
};
3233

3334
// The reads of the value of variables in a returned expression that are the

‎cpp2rust/converter/models/converter_refcount.cpp‎

Lines changed: 0 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -2258,86 +2258,6 @@ bool ConverterRefCount::VisitCXXDeleteExpr(clang::CXXDeleteExpr *expr) {
22582258
return false;
22592259
}
22602260

2261-
void ConverterRefCount::EmitByValueShadow(const clang::VarDecl *loop_var,
2262-
std::string box_expr,
2263-
const std::string &type_override) {
2264-
auto type = loop_var->getType();
2265-
if (!type->isReferenceType()) {
2266-
bool unboxed = IsUnboxedVar(loop_var);
2267-
PushConversionKind push(*this, VarConversionKind(loop_var));
2268-
auto type_str = type_override.empty() ? ToString(type) : type_override;
2269-
StrCat(keyword::kLet, unboxed ? keyword::kMut : "",
2270-
GetNamedDeclAsString(loop_var), token::kColon, type_str,
2271-
token::kAssign);
2272-
StrCat(BoxValue(std::move(box_expr)), token::kSemiColon);
2273-
}
2274-
}
2275-
2276-
bool ConverterRefCount::VisitCXXForRangeStmtMap(clang::CXXForRangeStmt *stmt) {
2277-
auto begin =
2278-
llvm::cast<clang::VarDecl>(stmt->getBeginStmt()->getSingleDecl());
2279-
auto begin_name = GetNamedDeclAsString(begin);
2280-
2281-
StrCat("'loop_:");
2282-
StrCat(keyword::kFor, begin_name, keyword::kIn, "Map::range(",
2283-
ConvertObject(stmt->getRangeInit()), ')');
2284-
PushBrace brace(*this);
2285-
2286-
EmitByValueShadow(begin, std::string(begin_name));
2287-
Convert(stmt->getLoopVarStmt());
2288-
2289-
ConvertForRangeBody(stmt);
2290-
2291-
return false;
2292-
}
2293-
2294-
bool ConverterRefCount::VisitCXXForRangeStmtVector(
2295-
clang::CXXForRangeStmt *stmt) {
2296-
auto *loop_var = stmt->getLoopVariable();
2297-
auto loop_var_name = GetNamedDeclAsString(loop_var);
2298-
2299-
StrCat("'loop_:");
2300-
StrCat(keyword::kFor,
2301-
stmt->getLoopVariable()->getType().isConstQualified() ? "" : "mut",
2302-
loop_var_name, keyword::kIn,
2303-
ConvertObject(stmt->getRangeInit(), ObjectShape::Element));
2304-
StrCat(keyword::kAs, ConvertPtrType(stmt->getRangeInit()->getType()));
2305-
2306-
PushBrace brace(*this);
2307-
2308-
auto type = loop_var->getType();
2309-
bool copy = type.isPODType(ctx_) && !type->isRecordType();
2310-
EmitByValueShadow(loop_var, loop_var_name + GetPointerDerefSuffix(type) +
2311-
(copy ? "" : ".clone()"));
2312-
2313-
ConvertForRangeBody(stmt);
2314-
2315-
return false;
2316-
}
2317-
2318-
bool ConverterRefCount::VisitCXXForRangeStmtString(
2319-
clang::CXXForRangeStmt *stmt) {
2320-
auto *loop_var = stmt->getLoopVariable();
2321-
auto loop_var_name = GetNamedDeclAsString(loop_var);
2322-
2323-
StrCat("'loop_:");
2324-
StrCat(keyword::kFor,
2325-
stmt->getLoopVariable()->getType().isConstQualified() ? "" : "mut",
2326-
loop_var_name, keyword::kIn,
2327-
ConvertObject(stmt->getRangeInit(), ObjectShape::Element));
2328-
StrCat(".to_string_iterator() as StringIterator<",
2329-
ToString(loop_var->getType().getNonReferenceType()), '>');
2330-
2331-
PushBrace brace(*this);
2332-
2333-
EmitByValueShadow(loop_var, loop_var_name +
2334-
GetPointerDerefSuffix(loop_var->getType()) +
2335-
".clone()");
2336-
ConvertForRangeBody(stmt);
2337-
2338-
return false;
2339-
}
2340-
23412261
bool ConverterRefCount::VisitArrayInitLoopExpr(clang::ArrayInitLoopExpr *expr) {
23422262
StrCat("Box::new");
23432263
PushParen outer(*this);

‎cpp2rust/converter/models/converter_refcount.h‎

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -214,15 +214,6 @@ class ConverterRefCount final : public Converter {
214214

215215
bool VisitCXXDeleteExpr(clang::CXXDeleteExpr *expr) override;
216216

217-
bool VisitCXXForRangeStmtMap(clang::CXXForRangeStmt *stmt) override;
218-
219-
bool VisitCXXForRangeStmtVector(clang::CXXForRangeStmt *stmt) override;
220-
221-
bool VisitCXXForRangeStmtString(clang::CXXForRangeStmt *stmt) override;
222-
223-
void EmitByValueShadow(const clang::VarDecl *loop_var, std::string box_expr,
224-
const std::string &type_override = "");
225-
226217
std::string ConvertStream(clang::Expr *expr) override;
227218

228219
bool VisitCXXConstructExpr(clang::CXXConstructExpr *expr) override;

‎docs/src/runtime/iterators.md‎

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,8 @@ for x in v.as_pointer() as Ptr<i32> {
2727
}
2828
```
2929

30-
Two variants serve special cases. `StringIterator`, returned by
31-
`to_string_iterator`, stops before the trailing zero byte, so iterating a
32-
`std::string` visits its characters only. `PtrValueIter` yields copies of the
33-
elements instead of pointers to them; rule bodies use it to feed a range of C
34-
memory to Rust iterator adaptors:
30+
`PtrValueIter` yields copies of the elements instead of pointers to them; rule
31+
bodies use it to feed a range of C memory to Rust iterator adaptors:
3532

3633
```rust
3734
// std::accumulate(first, last, init)

‎libcc2rs/src/iterators.rs‎

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,27 +24,3 @@ impl<T: CChar> Iterator for CStringIterator<T> {
2424
Some(ch)
2525
}
2626
}
27-
28-
impl<T> Ptr<T> {
29-
pub fn to_string_iterator(&self) -> StringIterator<T> {
30-
StringIterator { ptr: self.clone() }
31-
}
32-
}
33-
34-
pub struct StringIterator<T> {
35-
ptr: Ptr<T>,
36-
}
37-
38-
impl<T> Iterator for StringIterator<T> {
39-
type Item = Ptr<T>;
40-
fn next(&mut self) -> Option<Self::Item> {
41-
// stop before the null terminator at the last position
42-
if self.ptr.get_offset().wrapping_add(1) < self.ptr.len() {
43-
let value = self.ptr.clone();
44-
self.ptr += 1;
45-
Some(value)
46-
} else {
47-
None
48-
}
49-
}
50-
}

0 commit comments

Comments
 (0)