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
57 changes: 57 additions & 0 deletions cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5301,6 +5301,42 @@ std::string Converter::ConvertGenericCall(
assert(call_args.empty() && "default takes no arguments");
return GetUnboxedDefaultAsString(type);
}
if (call.method == "move_ctor") {
assert(call_args.size() == 1 && "move_ctor takes one argument");
auto *record = type->getAsCXXRecordDecl();
if (record && HasMoveFromConstructor(record)) {
return std::format("{}::move_from({})", GetUnboxedTypeAsString(type),
call_args[0]);
}
if (record && !IsUserDefinedDecl(record) &&
!record->hasTrivialMoveConstructor()) {
return std::format("<{} as {}>::move_ctor({})",
GetUnboxedTypeAsString(type), GetMoveCtorTraitName(),
call_args[0]);
}
return ConvertPtrRead(type, call_args[0]);
}
if (call.method == "move_assign" || call.method == "copy_assign") {
assert(call_args.size() == 2 && "assignments take two arguments");
bool is_move = call.method == "move_assign";
auto *record = type->getAsCXXRecordDecl();
if (record && is_move && HasMoveAssignOperator(record)) {
return ConvertPointeeMethodCall("move_assign", call_args[0],
call_args[1]);
}
if (record && HasCopyAssignOperator(record)) {
return ConvertPointeeMethodCall("copy_assign", call_args[0],
call_args[1]);
}
if (is_move && record && !IsUserDefinedDecl(record) &&
!record->hasTrivialMoveAssignment()) {
return ConvertPtrWrite(call_args[0],
std::format("<{} as {}>::move_ctor({})",
GetUnboxedTypeAsString(type),
GetMoveCtorTraitName(), call_args[1]));
}
return ConvertPtrWrite(call_args[0], ConvertPtrRead(type, call_args[1]));
}
if (call.method == "cpp_from" || call.method == "cpp_from_move") {
assert(call_args.size() == 1 && "cpp_from takes one argument");
return ConvertConversion(
Expand Down Expand Up @@ -5337,6 +5373,27 @@ const char *Converter::GetConversionTraitName() const {
return "CppFromUnsafe";
}

std::string Converter::ConvertPtrRead(clang::QualType type,
const std::string &src) {
if (type->isScalarType()) {
return std::format("(*{})", src);
}
return std::format("(*{}).clone()", src);
}

std::string Converter::ConvertPtrWrite(const std::string &dst,
const std::string &value) {
return std::format("*{} = {}", dst, value);
}

std::string Converter::ConvertPointeeMethodCall(const char *method,
const std::string &dst,
const std::string &src) {
return std::format("(*{}).{}({})", dst, method, src);
}

const char *Converter::GetMoveCtorTraitName() const { return "MoveCtorUnsafe"; }

std::string Converter::DerefPtrExpr(std::string_view ptr_expr,
clang::QualType pointee_type) {
return std::format("({}{})", GetPointerDerefPrefix(pointee_type), ptr_expr);
Expand Down
12 changes: 12 additions & 0 deletions cpp2rust/converter/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,18 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {

virtual const char *GetConversionTraitName() const;

virtual std::string ConvertPtrRead(clang::QualType type,
const std::string &src);

virtual std::string ConvertPtrWrite(const std::string &dst,
const std::string &value);

virtual std::string ConvertPointeeMethodCall(const char *method,
const std::string &dst,
const std::string &src);

virtual const char *GetMoveCtorTraitName() const;

virtual std::string DerefPtrExpr(std::string_view ptr_expr,
clang::QualType pointee_type);

Expand Down
12 changes: 12 additions & 0 deletions cpp2rust/converter/mapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@ std::string Map(Converter &converter, clang::QualType qual_type) {
return {};
}

std::optional<TranslationRule::Elems> Elems(Converter &converter,
clang::QualType qual_type) {
auto [rule, subs] =
RuleRegistry::Search(converter.GetASTContext(), qual_type);
if (!rule || !rule->type_info.elems) {
return std::nullopt;
}
auto &elems = *rule->type_info.elems;
return TranslationRule::Elems{
elems.kind, Matcher::InstantiateTgt(converter, subs, elems.type)};
}

std::string MapInitializer(Converter &converter, clang::QualType qual_type) {
auto [rule, subs] =
RuleRegistry::Search(converter.GetASTContext(), qual_type);
Expand Down
3 changes: 3 additions & 0 deletions cpp2rust/converter/mapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <clang/AST/Expr.h>
#include <clang/AST/Type.h>

#include <optional>
#include <string>

#include "converter/translation_rule.h"
Expand All @@ -22,6 +23,8 @@ bool IsRefExpr(clang::ASTContext &ctx, const clang::Expr *expr);

std::string Map(clang::ASTContext &ctx, clang::QualType qual_type);
std::string Map(Converter &converter, clang::QualType qual_type);
std::optional<TranslationRule::Elems> Elems(Converter &converter,
clang::QualType qual_type);
std::string MapInitializer(Converter &converter, clang::QualType qual_type);
std::string MapFunctionName(clang::ASTContext &ctx,
const clang::FunctionDecl *decl);
Expand Down
78 changes: 40 additions & 38 deletions cpp2rust/converter/models/converter_refcount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,13 @@ use std::rc::{Rc, Weak};
)");
}

static bool IsBoxedType(std::string_view type) {
return type.starts_with("Vec<") || type.starts_with("Box<");
bool ConverterRefCount::IsBoxedType(clang::QualType type) {
return Mapper::Elems(*this, type.getUnqualifiedType()).has_value();
}

static bool IsBoxedType(clang::ASTContext &ctx, clang::QualType type) {
return IsBoxedType(Mapper::Map(ctx, type.getUnqualifiedType()));
bool ConverterRefCount::IsVecType(clang::QualType type) {
auto elems = Mapper::Elems(*this, type.getUnqualifiedType());
return elems && elems->kind == TranslationRule::ElemsKind::kVec;
}

// A Rust type without whitespace, and with the paths into libcc2rs, which the
Expand All @@ -73,11 +74,9 @@ static std::string NormalizeType(std::string type) {

// Virtual methods take &mut self, as the fields of the struct are stored in
// it.
static bool NeedsMutAccess(clang::ASTContext &ctx,
const clang::CXXMethodDecl *method,
clang::QualType base_type) {
return !method->isConst() &&
(IsBoxedType(ctx, base_type) || method->isVirtual());
bool ConverterRefCount::NeedsMutAccess(const clang::CXXMethodDecl *method,
clang::QualType base_type) {
return !method->isConst() && (IsBoxedType(base_type) || method->isVirtual());
}

// Whether `expr` is an array field whose elements are accessed through
Expand Down Expand Up @@ -135,19 +134,6 @@ void ConverterRefCount::PendingDeref::set_unchecked(std::string str,
type = ComputedExprType::Pending;
}

std::string ConverterRefCount::GetInnerType(clang::QualType type) {
PushConversionKind push(*this, ConversionKind::Unboxed);
auto str = ToString(type);
auto pos = str.find('<');
auto end = str.rfind('>');
if (str[pos + 1] == '[' && str[end - 1] == ']') {
// Unwrap inner array type
pos++;
end--;
}
return std::move(str).substr(pos + 1, end - pos - 1);
}

std::string
ConverterRefCount::GetSafeTypeAsString(clang::QualType qual_type) const {
std::string type_as_string;
Expand Down Expand Up @@ -383,7 +369,7 @@ std::string ConverterRefCount::ConvertObject(clang::Expr *expr,
if (is_ptr) {
type = type->getPointeeType();
}
if (IsBoxedType(ctx_, type) || (is_ptr && type->isArrayType())) {
if (IsBoxedType(type) || (is_ptr && type->isArrayType())) {
MarkFresh();
return std::move(str) + ".decay()";
}
Expand All @@ -393,7 +379,7 @@ std::string ConverterRefCount::ConvertObject(clang::Expr *expr,

std::string ConverterRefCount::AsPointerMethod(clang::QualType type) {
if (isObject() && object_shape_ == ObjectShape::Element &&
type->isRecordType() && IsBoxedType(ctx_, type)) {
type->isRecordType() && IsBoxedType(type)) {
object_shape_ = ObjectShape::Whole;
return ".decay()";
}
Expand All @@ -419,7 +405,7 @@ bool ConverterRefCount::ParamIsElementPtr(clang::Expr *expr, clang::Expr *arg,
type = type->getPointeeType();
}
type = type.getUnqualifiedType();
if (!IsBoxedType(ctx_, type)) {
if (!IsBoxedType(type)) {
return false;
}
// The C++ parameter is a reference or pointer to the container, which the
Expand Down Expand Up @@ -531,9 +517,9 @@ ConverterRefCount::MaterializeTemp(const std::string &binding_name,

std::string ConverterRefCount::ConvertPtrType(clang::QualType type) {
std::string str;
// decays into Ptr; remove the outer type Vec<>
if (IsBoxedType(ctx_, type)) {
str = GetInnerType(type);
if (auto elems = Mapper::Elems(*this, type.getUnqualifiedType())) {
PushConversionKind push(*this, ConversionKind::Unboxed);
str = std::move(elems->type);
} else {
PushConversionKind push(*this, ConversionKind::Ptr);
str = ToString(type);
Expand Down Expand Up @@ -768,7 +754,7 @@ void ConverterRefCount::EmitByteSizeAttr(const clang::RecordDecl *decl) {

std::string
ConverterRefCount::GetSelfMaybeWithMut(const clang::CXXMethodDecl *decl) {
return NeedsMutAccess(ctx_, decl, decl->getThisType()->getPointeeType())
return NeedsMutAccess(decl, decl->getThisType()->getPointeeType())
? "&mut self"
: "&self";
}
Expand Down Expand Up @@ -1776,7 +1762,7 @@ bool ConverterRefCount::VisitMemberExpr(clang::MemberExpr *expr) {
if (base_type->isPointerType()) {
base_type = base_type->getPointeeType();
}
bool needs_mut = NeedsMutAccess(ctx_, method, base_type);
bool needs_mut = NeedsMutAccess(method, base_type);
PushExprKind push(*this, needs_mut ? ExprKind::LValue : ExprKind::RValue);
Converter::ConvertMemberExpr(expr);
MarkFresh();
Expand Down Expand Up @@ -1845,7 +1831,7 @@ void ConverterRefCount::ConvertInlineField(clang::MemberExpr *expr) {
if (type->isArrayType()) {
StrCat(std::format("array_field_ptr!({}, {})", ConvertRecordPtr(expr),
name));
} else if (IsBoxedType(ctx_, type)) {
} else if (IsBoxedType(type)) {
StrCat(std::format("field_ref!({}, {}){}", ConvertRecordPtr(expr), name,
AsPointerMethod(type)));
} else {
Expand Down Expand Up @@ -2271,6 +2257,25 @@ const char *ConverterRefCount::GetConversionTraitName() const {
return "CppFrom";
}

std::string ConverterRefCount::ConvertPtrRead(clang::QualType,
const std::string &src) {
return std::format("{}.read()", src);
}

std::string ConverterRefCount::ConvertPtrWrite(const std::string &dst,
const std::string &value) {
return std::format("{}.write({})", dst, value);
}

std::string ConverterRefCount::ConvertPointeeMethodCall(
const char *method, const std::string &dst, const std::string &src) {
return std::format("{}.{}({})", dst, method, src);
}

const char *ConverterRefCount::GetMoveCtorTraitName() const {
return "MoveCtor";
}

bool ConverterRefCount::TypeDerivesDefault(clang::QualType qual_type) {
// Arrays are translated to Value<Box<[T]>>, whose Default is empty
return !qual_type->isArrayType() && Converter::TypeDerivesDefault(qual_type);
Expand Down Expand Up @@ -2483,8 +2488,8 @@ bool ConverterRefCount::ConvertCXXOperatorCallExpr(

case clang::OverloadedOperatorKind::OO_Subscript: {
bool is_inner_boxed =
IsBoxedType(ctx_, expr->getType().getNonReferenceType()) &&
IsBoxedType(ctx_, expr->getArg(0)->getType().getNonReferenceType());
IsBoxedType(expr->getType().getNonReferenceType()) &&
IsBoxedType(expr->getArg(0)->getType().getNonReferenceType());

// An element of an unboxed container is accessed directly, as is one of
// a container stored in a Value that can be borrowed.
Expand Down Expand Up @@ -2583,9 +2588,7 @@ std::string ConverterRefCount::ConvertElemPlace(clang::Expr *container,
: nullptr;
if (field && !field->getType()->isReferenceType() &&
!field->getParent()->isUnion() && !Mapper::Contains(ctx_, member) &&
!IsUnboxedPlace(member) &&
Mapper::Map(ctx_, field->getType().getUnqualifiedType())
.starts_with("Vec<")) {
!IsUnboxedPlace(member) && IsVecType(field->getType())) {
if (IsFieldOfVectorElem(member)) {
return std::format("index!({}, {})", ConvertPlace(member),
ConvertSubscriptIndex(idx));
Expand All @@ -2600,8 +2603,7 @@ std::string ConverterRefCount::ConvertElemPlace(clang::Expr *container,
container->IgnoreParenNoopCasts(ctx_));
if ((IsReferenceType(container) ||
(deref && deref->getOpcode() == clang::UO_Deref)) &&
Mapper::Map(ctx_, container->getType().getUnqualifiedType())
.starts_with("Vec<")) {
IsVecType(container->getType())) {
ConvertLValue(container);
if (!pending_deref_.empty()) {
auto place = pending_deref_.take();
Expand Down
18 changes: 17 additions & 1 deletion cpp2rust/converter/models/converter_refcount.h
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,23 @@ class ConverterRefCount final : public Converter {

const char *GetConversionTraitName() const override;

std::string GetInnerType(clang::QualType type);
std::string ConvertPtrRead(clang::QualType type,
const std::string &src) override;

std::string ConvertPtrWrite(const std::string &dst,
const std::string &value) override;

std::string ConvertPointeeMethodCall(const char *method,
const std::string &dst,
const std::string &src) override;

const char *GetMoveCtorTraitName() const override;

bool IsBoxedType(clang::QualType type);
bool IsVecType(clang::QualType type);

bool NeedsMutAccess(const clang::CXXMethodDecl *method,
clang::QualType base_type);

// What an Object-kind conversion of a boxed container/array should yield:
// a pointer to the whole object (Ptr<Vec<T>>), or one to its first
Expand Down
10 changes: 10 additions & 0 deletions cpp2rust/converter/translation_rule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ TypeInfo ParseTypeInfoJSON(const llvm::json::Object &obj) {
info.derives.emplace_back(s->str());
}
}
if (auto *elems = obj.getObject("elems")) {
auto kind = elems->getString("kind");
auto type = elems->getString("type");
assert(kind && type);
assert(*kind == "vec" || *kind == "array");
info.elems = Elems{*kind == "vec" ? ElemsKind::kVec : ElemsKind::kArray,
type->str()};
}
return info;
}

Expand Down Expand Up @@ -346,6 +354,8 @@ void TypeInfo::dump() const {
log() << " [rc_ptr]";
if (is_unsafe_pointer)
log() << " [unsafe_ptr]";
if (elems)
log() << " [elems " << elems->type << ']';
for (const auto &d : derives)
log() << " +" << d;
}
Expand Down
9 changes: 9 additions & 0 deletions cpp2rust/converter/translation_rule.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <llvm/Support/JSON.h>

#include <filesystem>
#include <optional>
#include <string>
#include <variant>
#include <vector>
Expand Down Expand Up @@ -93,12 +94,20 @@ struct Bound {
bool AnyFragment(const std::vector<BodyFragment> &body,
llvm::function_ref<bool(const BodyFragment &)> pred);

enum class ElemsKind { kVec, kArray };

struct Elems {
ElemsKind kind;
std::string type;
};

struct TypeInfo {
std::vector<std::string> derives;
std::string type;
std::string cpp_type;
bool is_refcount_pointer = false;
bool is_unsafe_pointer = false;
std::optional<Elems> elems;

bool is_pointer() const { return is_refcount_pointer || is_unsafe_pointer; }

Expand Down
Loading
Loading