Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 20 additions & 99 deletions cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1372,6 +1372,9 @@ bool Converter::VisitDeclStmt(clang::DeclStmt *stmt) {
hoisted_records_ += std::move(buf).str();
continue;
}
if (var && IsAliasOfInit(ctx_, var)) {
continue;
}
if (var && var->isImplicit()) {
VisitVarDecl(var);
} else {
Expand Down Expand Up @@ -1487,112 +1490,25 @@ bool Converter::VisitForStmt(clang::ForStmt *stmt) {
return false;
}

void Converter::ConvertLoopVariable(clang::VarDecl *decl,
clang::Expr *range_init) {
auto loop_var_type = decl->getType();
auto loop_var_name = GetNamedDeclAsString(decl);

if (loop_var_type->isReferenceType()) {
auto pointee_type = loop_var_type->getPointeeType();
Convert(range_init);
if (pointee_type.isConstQualified()) {
StrCat(std::format(".as_ptr().add({})", loop_var_name));
} else {
StrCat(std::format(".as_mut_ptr().add({})", loop_var_name));
}
} else {
{
PushExplicitAutoref autoref(*this, /*is_mut=*/false);
Convert(range_init);
}
StrCat(std::format("[{}]", loop_var_name));
StrCat(".clone()");
}
}

void Converter::ConvertForRangeBody(clang::CXXForRangeStmt *stmt) {
PushBreakTarget push(break_target_, BreakTarget::Loop);
curr_for_inc_.emplace_back(nullptr);
ConvertBodyStmts(stmt->getBody());
curr_for_inc_.pop_back();
}

bool Converter::VisitCXXForRangeStmt(clang::CXXForRangeStmt *stmt) {
auto range_init_type = stmt->getRangeInit()->getType();

if (!Mapper::Contains(ctx_, range_init_type.getUnqualifiedType())) {
// FIXME: improve error handling
log() << "for range stmts only for types in std namespace\n";
}

log() << "GetClassName: " << GetClassName(range_init_type) << '\n';

if (GetClassName(range_init_type) == "std::map") {
return VisitCXXForRangeStmtMap(stmt);
}
if (GetClassName(range_init_type) == "std::basic_string") {
return VisitCXXForRangeStmtString(stmt);
}
return VisitCXXForRangeStmtVector(stmt);
}

bool Converter::VisitCXXForRangeStmtMap(clang::CXXForRangeStmt *stmt) {
auto begin =
llvm::cast<clang::VarDecl>(stmt->getBeginStmt()->getSingleDecl());

PushBreakTarget push(break_target_, BreakTarget::Loop);
Convert(stmt->getInit());
Convert(stmt->getRangeStmt());
auto *begin =
clang::cast<clang::VarDecl>(stmt->getBeginStmt()->getSingleDecl());
auto *end = clang::cast<clang::VarDecl>(stmt->getEndStmt()->getSingleDecl());
begin->setDeclName(stmt->getLoopVariable()->getDeclName());
StrCat("'loop_:");
auto map_type = Mapper::Map(*this, stmt->getRangeInit()->getType());
StrCat(keyword::kFor, GetNamedDeclAsString(begin), keyword::kIn,
"UnsafeMap::range(&");
Convert(stmt->getRangeInit());
StrCat(std::format(" as *const {})", map_type));
"IterRange::new(", ConvertFreshRValue(begin->getInit()), token::kComma,
ConvertFreshRValue(end->getInit()), ')');
{
PushBrace brace(*this);
curr_for_inc_.emplace_back(nullptr);
Convert(stmt->getLoopVarStmt());
ConvertForRangeBody(stmt);
}

return false;
}

bool Converter::VisitCXXForRangeStmtString(clang::CXXForRangeStmt *stmt) {
return VisitCXXForRangeStmtIndexBased(stmt, "len()-1");
}

bool Converter::VisitCXXForRangeStmtVector(clang::CXXForRangeStmt *stmt) {
return VisitCXXForRangeStmtIndexBased(stmt, "len()");
}

bool Converter::VisitCXXForRangeStmtIndexBased(clang::CXXForRangeStmt *stmt,
const char *len_suffix) {
auto *loop_var = stmt->getLoopVariable();
auto loop_var_name = GetNamedDeclAsString(loop_var);

StrCat("'loop_:");
StrCat(keyword::kFor, loop_var_name, keyword::kIn, "0..");
{
PushParen range(*this);
Convert(stmt->getRangeInit());
StrCat(token::kDot, len_suffix);
}
{
PushBrace body(*this);
StrCat(keyword::kLet);

auto loop_var_type = loop_var->getType();
if (!loop_var_type.isConstQualified()) {
StrCat(keyword_mut_);
}

StrCat(loop_var_name);
StrCat(token::kAssign);

ConvertLoopVariable(loop_var, stmt->getRangeInit());

StrCat(token::kSemiColon);
ConvertForRangeBody(stmt);
ConvertBodyStmts(stmt->getBody());
curr_for_inc_.pop_back();
}

return false;
}

Expand Down Expand Up @@ -3268,6 +3184,11 @@ bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) {
Convert(init);
return false;
}
if (auto var = clang::dyn_cast<clang::VarDecl>(expr->getDecl());
var && IsAliasOfInit(ctx_, var)) {
Convert(var->getInit());
return false;
}
ConvertDeclRefValue(expr, expr->getDecl());
return false;
}
Expand Down
14 changes: 0 additions & 14 deletions cpp2rust/converter/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,17 +223,6 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {

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

virtual bool VisitCXXForRangeStmtMap(clang::CXXForRangeStmt *stmt);

virtual bool VisitCXXForRangeStmtVector(clang::CXXForRangeStmt *stmt);

virtual bool VisitCXXForRangeStmtString(clang::CXXForRangeStmt *stmt);

bool VisitCXXForRangeStmtIndexBased(clang::CXXForRangeStmt *stmt,
const char *len_suffix);

void ConvertForRangeBody(clang::CXXForRangeStmt *stmt);

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

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

virtual void ConvertLoopVariable(clang::VarDecl *decl,
clang::Expr *range_init);

virtual bool ConvertCXXOperatorCallExpr(clang::CXXOperatorCallExpr *expr);

std::string GetMappedAsString(clang::Expr *expr, clang::Expr **args = nullptr,
Expand Down
8 changes: 4 additions & 4 deletions cpp2rust/converter/converter_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1920,10 +1920,10 @@ std::optional<clang::QualType> GetParamImplicitConvertTarget(clang::Expr *expr,
return fn->getParamDecl(param_idx)->getType().getNonReferenceType();
}

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

bool IsVaListType(clang::QualType type) {
Expand Down
4 changes: 2 additions & 2 deletions cpp2rust/converter/converter_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -321,10 +321,10 @@ clang::Expr *BuildInitExpr(clang::Sema &sema, clang::QualType type,
llvm::ArrayRef<clang::Expr *> args,
clang::SourceLocation loc);

std::string GetClassName(clang::QualType type);

bool IsVaListType(clang::QualType type);

bool IsAliasOfInit(clang::ASTContext &ctx, const clang::VarDecl *var);

bool NeedsImplicitScalarCast(clang::ASTContext &ctx, clang::QualType from,
clang::QualType to);

Expand Down
19 changes: 15 additions & 4 deletions cpp2rust/converter/models/boxed_vars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,17 @@ class AddressTakenVisitor
: public clang::RecursiveASTVisitor<AddressTakenVisitor> {
public:
AddressTakenVisitor(clang::ASTContext &ctx,
std::unordered_set<const clang::VarDecl *> &vars)
: ctx_(ctx), address_taken_(vars) {}
std::unordered_set<const clang::VarDecl *> &vars,
std::unordered_set<const clang::VarDecl *> &iterators)
: ctx_(ctx), address_taken_(vars), range_iterators_(iterators) {}

bool VisitCXXForRangeStmt(clang::CXXForRangeStmt *stmt) {
if (auto *begin = stmt->getBeginStmt()) {
range_iterators_.insert(
clang::cast<clang::VarDecl>(begin->getSingleDecl()));
}
return true;
}

bool shouldVisitTemplateInstantiations() const { return true; }

Expand Down Expand Up @@ -249,18 +258,20 @@ class AddressTakenVisitor

clang::ASTContext &ctx_;
std::unordered_set<const clang::VarDecl *> &address_taken_;
std::unordered_set<const clang::VarDecl *> &range_iterators_;
// The references to variables that only access their value.
std::unordered_set<const clang::DeclRefExpr *> value_uses_;
};
} // namespace

BoxedVars::BoxedVars(clang::ASTContext &ctx) : ctx_(ctx) {
AddressTakenVisitor(ctx, address_taken_)
AddressTakenVisitor(ctx, address_taken_, range_iterators_)
.TraverseDecl(ctx.getTranslationUnitDecl());
}

bool BoxedVars::contains(const clang::VarDecl *decl) const {
return !CanUnbox(ctx_, decl) || address_taken_.contains(decl);
return !range_iterators_.contains(decl) &&
(!CanUnbox(ctx_, decl) || address_taken_.contains(decl));
}

namespace {
Expand Down
1 change: 1 addition & 0 deletions cpp2rust/converter/models/boxed_vars.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class BoxedVars {
private:
clang::ASTContext &ctx_;
std::unordered_set<const clang::VarDecl *> address_taken_;
std::unordered_set<const clang::VarDecl *> range_iterators_;
};

// The reads of the value of variables in a returned expression that are the
Expand Down
80 changes: 0 additions & 80 deletions cpp2rust/converter/models/converter_refcount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2258,86 +2258,6 @@ bool ConverterRefCount::VisitCXXDeleteExpr(clang::CXXDeleteExpr *expr) {
return false;
}

void ConverterRefCount::EmitByValueShadow(const clang::VarDecl *loop_var,
std::string box_expr,
const std::string &type_override) {
auto type = loop_var->getType();
if (!type->isReferenceType()) {
bool unboxed = IsUnboxedVar(loop_var);
PushConversionKind push(*this, VarConversionKind(loop_var));
auto type_str = type_override.empty() ? ToString(type) : type_override;
StrCat(keyword::kLet, unboxed ? keyword::kMut : "",
GetNamedDeclAsString(loop_var), token::kColon, type_str,
token::kAssign);
StrCat(BoxValue(std::move(box_expr)), token::kSemiColon);
}
}

bool ConverterRefCount::VisitCXXForRangeStmtMap(clang::CXXForRangeStmt *stmt) {
auto begin =
llvm::cast<clang::VarDecl>(stmt->getBeginStmt()->getSingleDecl());
auto begin_name = GetNamedDeclAsString(begin);

StrCat("'loop_:");
StrCat(keyword::kFor, begin_name, keyword::kIn, "Map::range(",
ConvertObject(stmt->getRangeInit()), ')');
PushBrace brace(*this);

EmitByValueShadow(begin, std::string(begin_name));
Convert(stmt->getLoopVarStmt());

ConvertForRangeBody(stmt);

return false;
}

bool ConverterRefCount::VisitCXXForRangeStmtVector(
clang::CXXForRangeStmt *stmt) {
auto *loop_var = stmt->getLoopVariable();
auto loop_var_name = GetNamedDeclAsString(loop_var);

StrCat("'loop_:");
StrCat(keyword::kFor,
stmt->getLoopVariable()->getType().isConstQualified() ? "" : "mut",
loop_var_name, keyword::kIn,
ConvertObject(stmt->getRangeInit(), ObjectShape::Element));
StrCat(keyword::kAs, ConvertPtrType(stmt->getRangeInit()->getType()));

PushBrace brace(*this);

auto type = loop_var->getType();
bool copy = type.isPODType(ctx_) && !type->isRecordType();
EmitByValueShadow(loop_var, loop_var_name + GetPointerDerefSuffix(type) +
(copy ? "" : ".clone()"));

ConvertForRangeBody(stmt);

return false;
}

bool ConverterRefCount::VisitCXXForRangeStmtString(
clang::CXXForRangeStmt *stmt) {
auto *loop_var = stmt->getLoopVariable();
auto loop_var_name = GetNamedDeclAsString(loop_var);

StrCat("'loop_:");
StrCat(keyword::kFor,
stmt->getLoopVariable()->getType().isConstQualified() ? "" : "mut",
loop_var_name, keyword::kIn,
ConvertObject(stmt->getRangeInit(), ObjectShape::Element));
StrCat(".to_string_iterator() as StringIterator<",
ToString(loop_var->getType().getNonReferenceType()), '>');

PushBrace brace(*this);

EmitByValueShadow(loop_var, loop_var_name +
GetPointerDerefSuffix(loop_var->getType()) +
".clone()");
ConvertForRangeBody(stmt);

return false;
}

bool ConverterRefCount::VisitArrayInitLoopExpr(clang::ArrayInitLoopExpr *expr) {
StrCat("Box::new");
PushParen outer(*this);
Expand Down
9 changes: 0 additions & 9 deletions cpp2rust/converter/models/converter_refcount.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,15 +214,6 @@ class ConverterRefCount final : public Converter {

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

bool VisitCXXForRangeStmtMap(clang::CXXForRangeStmt *stmt) override;

bool VisitCXXForRangeStmtVector(clang::CXXForRangeStmt *stmt) override;

bool VisitCXXForRangeStmtString(clang::CXXForRangeStmt *stmt) override;

void EmitByValueShadow(const clang::VarDecl *loop_var, std::string box_expr,
const std::string &type_override = "");

std::string ConvertStream(clang::Expr *expr) override;

bool VisitCXXConstructExpr(clang::CXXConstructExpr *expr) override;
Expand Down
7 changes: 2 additions & 5 deletions docs/src/runtime/iterators.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,8 @@ for x in v.as_pointer() as Ptr<i32> {
}
```

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

```rust
// std::accumulate(first, last, init)
Expand Down
24 changes: 0 additions & 24 deletions libcc2rs/src/iterators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,3 @@ impl<T: CChar> Iterator for CStringIterator<T> {
Some(ch)
}
}

impl<T> Ptr<T> {
pub fn to_string_iterator(&self) -> StringIterator<T> {
StringIterator { ptr: self.clone() }
}
}

pub struct StringIterator<T> {
ptr: Ptr<T>,
}

impl<T> Iterator for StringIterator<T> {
type Item = Ptr<T>;
fn next(&mut self) -> Option<Self::Item> {
// stop before the null terminator at the last position
if self.ptr.get_offset().wrapping_add(1) < self.ptr.len() {
let value = self.ptr.clone();
self.ptr += 1;
Some(value)
} else {
None
}
}
}
Loading
Loading