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
44 changes: 31 additions & 13 deletions cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ std::string Converter::GetUnboxedTypeAsString(clang::QualType qual_type) {
return ToString(qual_type);
}

std::string Converter::GetUnboxedDefaultAsString(clang::QualType qual_type) {
return GetDefaultAsString(qual_type);
}

std::string
Converter::GetTemplateArgumentAsString(const clang::TemplateArgument &arg) {
switch (arg.getKind()) {
Expand Down Expand Up @@ -5041,15 +5045,16 @@ std::string Converter::ConvertTake(clang::Expr *arg) {

std::string Converter::ConvertMappedMethodCall(
clang::Expr *expr, const TranslationRule::MethodCallFragment &mc,
clang::Expr **args, unsigned num_args, TempMaterializationCtx *ctx) {
return ConvertIRFragment(mc.receiver, expr, args, num_args, ctx) +
ConvertIRFragment(mc.body, expr, args, num_args, ctx);
llvm::ArrayRef<clang::TemplateArgument> bindings, clang::Expr **args,
unsigned num_args, TempMaterializationCtx *ctx) {
return ConvertIRFragment(mc.receiver, bindings, expr, args, num_args, ctx) +
ConvertIRFragment(mc.body, bindings, expr, args, num_args, ctx);
}

std::string Converter::GetMappedAsString(clang::Expr *expr, clang::Expr **args,
unsigned num_args,
TempMaterializationCtx *ctx) {
auto *tgt_ir = RuleRegistry::GetExprRule(ctx_, expr);
auto [tgt_ir, bindings] = RuleRegistry::Search(ctx_, expr);
if (!tgt_ir)
return {};

Expand All @@ -5058,8 +5063,8 @@ std::string Converter::GetMappedAsString(clang::Expr *expr, clang::Expr **args,
auto saved_borrows = std::exchange(mut_borrows_, {});
auto *operand = tgt_ir->refExprOperand();
bool lvalue = operand && !isAddrOf();
auto result = ConvertIRFragment(lvalue ? *operand : tgt_ir->body, expr, args,
num_args, ctx);
auto result = ConvertIRFragment(lvalue ? *operand : tgt_ir->body, bindings,
expr, args, num_args, ctx);
if (tgt_ir->multi_statement) {
result = '{' + result + '}';
}
Expand All @@ -5073,19 +5078,28 @@ std::string Converter::GetMappedAsString(clang::Expr *expr, clang::Expr **args,

std::string Converter::ConvertIRFragment(
const std::vector<TranslationRule::BodyFragment> &fragments,
clang::Expr *expr, clang::Expr **args, unsigned num_args,
TempMaterializationCtx *ctx) {
llvm::ArrayRef<clang::TemplateArgument> bindings, clang::Expr *expr,
clang::Expr **args, unsigned num_args, TempMaterializationCtx *ctx) {
using namespace TranslationRule;

auto all_args = BuildUnifiedArgs(expr, args, num_args);
std::vector<clang::Expr *> all_args;
if (expr) {
all_args = BuildUnifiedArgs(expr, args, num_args);
}

std::string result;
for (auto &frag : fragments) {
if (auto *t = std::get_if<TextFragment>(&frag)) {
result += t->text;
} else if (auto *g = std::get_if<GenericFragment>(&frag)) {
result += Mapper::InstantiateTemplate(*this, expr, g->n);
result += GetTemplateArgumentAsString(bindings[g->n - 1]);
} else if (auto *d = std::get_if<DefaultFragment>(&frag)) {
auto &arg = bindings[d->n - 1];
assert(arg.getKind() == clang::TemplateArgument::Type &&
"default of a non-type generic");
result += GetUnboxedDefaultAsString(arg.getAsType());
} else if (auto *ph = std::get_if<PlaceholderFragment>(&frag)) {
assert(expr && "placeholder outside an expression rule");
auto arg_idx = ph->n;
assert(arg_idx < all_args.size());
auto *arg = all_args[arg_idx];
Expand All @@ -5110,16 +5124,20 @@ std::string Converter::ConvertIRFragment(
};
result += ConvertPlaceholder(expr, arg, ph_ctx);
} else if (std::get_if<TranslationRule::VaArgsFragment>(&frag)) {
assert(expr && "variadic arguments outside an expression rule");
result += ConvertVariadicTail(expr, all_args);
} else if (std::get_if<TranslationRule::InitFragment>(&frag)) {
assert(expr && "init outside an expression rule");
result += ConvertInitFragment(expr, all_args);
} else if (auto *mc =
std::get_if<std::unique_ptr<MethodCallFragment>>(&frag)) {
result += ConvertMappedMethodCall(expr, **mc, args, num_args, ctx);
result +=
ConvertMappedMethodCall(expr, **mc, bindings, args, num_args, ctx);
} else if (auto *re =
std::get_if<std::unique_ptr<RefExprFragment>>(&frag)) {
result += (*re)->prefix + ' ' +
ConvertIRFragment((*re)->inner, expr, args, num_args, ctx);
result +=
(*re)->prefix + ' ' +
ConvertIRFragment((*re)->inner, bindings, expr, args, num_args, ctx);
}
}

Expand Down
16 changes: 10 additions & 6 deletions cpp2rust/converter/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {

virtual std::string GetUnboxedTypeAsString(clang::QualType qual_type);

virtual std::string GetUnboxedDefaultAsString(clang::QualType qual_type);

std::string GetTemplateArgumentAsString(const clang::TemplateArgument &arg);

bool VisitRecoveryExpr(clang::RecoveryExpr *expr);
Expand Down Expand Up @@ -296,6 +298,12 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
std::vector<std::string> materialized_refs_;
};

std::string
ConvertIRFragment(const std::vector<TranslationRule::BodyFragment> &fragments,
llvm::ArrayRef<clang::TemplateArgument> bindings,
clang::Expr *expr, clang::Expr **args, unsigned num_args,
TempMaterializationCtx *ctx);

struct PlaceholderCtx {
unsigned arg_idx;
std::optional<clang::QualType> implicit_convert_to;
Expand Down Expand Up @@ -834,11 +842,6 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
unsigned num_args = 0,
TempMaterializationCtx *ctx = nullptr);

std::string
ConvertIRFragment(const std::vector<TranslationRule::BodyFragment> &fragments,
clang::Expr *expr, clang::Expr **args, unsigned num_args,
TempMaterializationCtx *ctx);

std::string ConvertPlaceholder(clang::Expr *expr, clang::Expr *arg,
const PlaceholderCtx &ph_ctx);

Expand Down Expand Up @@ -868,7 +871,8 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {

virtual std::string ConvertMappedMethodCall(
clang::Expr *expr, const TranslationRule::MethodCallFragment &mc,
clang::Expr **args, unsigned num_args, TempMaterializationCtx *ctx);
llvm::ArrayRef<clang::TemplateArgument> bindings, clang::Expr **args,
unsigned num_args, TempMaterializationCtx *ctx);

virtual std::string AccessLValueObject(clang::MemberExpr *member);

Expand Down
12 changes: 2 additions & 10 deletions cpp2rust/converter/mapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,6 @@ std::string MapFunctionName(clang::ASTContext &ctx,
return GetNamedDeclAsString(decl->getCanonicalDecl());
}

std::string InstantiateTemplate(Converter &converter, const clang::Expr *expr,
unsigned n) {
auto [rule, subs] = RuleRegistry::Search(converter.GetASTContext(), expr);
if (!rule) {
return std::format("T{}", n);
}
return Matcher::MapBinding(converter, subs, n - 1);
}

std::string Map(clang::ASTContext &ctx, clang::QualType qual_type) {
auto rule = RuleRegistry::Search(ctx, qual_type).first;
return rule ? rule->type_info.type : std::string();
Expand All @@ -71,7 +62,8 @@ std::string MapInitializer(Converter &converter, clang::QualType qual_type) {
auto [rule, subs] =
RuleRegistry::Search(converter.GetASTContext(), qual_type);
if (rule && !rule->initializer.empty()) {
return Matcher::InstantiateTgt(converter, subs, rule->initializer);
return converter.ConvertIRFragment(rule->initializer, subs, nullptr,
nullptr, 0, nullptr);
}
return {};
}
Expand Down
2 changes: 0 additions & 2 deletions cpp2rust/converter/mapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ std::string Map(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);
std::string InstantiateTemplate(Converter &converter, const clang::Expr *expr,
unsigned n);
std::string GetParamType(Converter &converter, const clang::Expr *expr,
unsigned index);
std::string GetReturnType(Converter &converter, const clang::Expr *expr);
Expand Down
26 changes: 18 additions & 8 deletions cpp2rust/converter/models/converter_refcount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,12 @@ ConverterRefCount::GetUnboxedTypeAsString(clang::QualType qual_type) {
return ToString(qual_type);
}

std::string
ConverterRefCount::GetUnboxedDefaultAsString(clang::QualType qual_type) {
PushConversionKind push(*this, ConversionKind::Unboxed);
return GetDefaultAsString(qual_type);
}

bool ConverterRefCount::Convert(clang::QualType qual_type) {
// Catch va_list before desugaring
if (IsVaListType(qual_type)) {
Expand Down Expand Up @@ -2971,11 +2977,13 @@ std::string ConverterRefCount::ConvertTake(clang::Expr *arg) {

std::string ConverterRefCount::ConvertMappedMethodCall(
clang::Expr *expr, const TranslationRule::MethodCallFragment &mc,
clang::Expr **args, unsigned num_args, TempMaterializationCtx *ctx) {
llvm::ArrayRef<clang::TemplateArgument> bindings, clang::Expr **args,
unsigned num_args, TempMaterializationCtx *ctx) {
auto receiver_ph = mc.getReceiverPlaceholder();
if (!receiver_ph || receiver_ph->access == TranslationRule::Access::kBorrow ||
receiver_ph->access == TranslationRule::Access::kMove) {
return Converter::ConvertMappedMethodCall(expr, mc, args, num_args, ctx);
return Converter::ConvertMappedMethodCall(expr, mc, bindings, args,
num_args, ctx);
}

auto arg_idx = receiver_ph->n;
Expand All @@ -2988,24 +2996,26 @@ std::string ConverterRefCount::ConvertMappedMethodCall(
auto param_type = Mapper::GetParamType(*this, expr, arg_idx);

if (arg->getType()->isPointerType()) {
return std::format("{}.with_mut(|__v: {}| __v{})", ConvertPointer(arg),
param_type,
ConvertIRFragment(mc.body, expr, args, num_args, ctx));
return std::format(
"{}.with_mut(|__v: {}| __v{})", ConvertPointer(arg), param_type,
ConvertIRFragment(mc.body, bindings, expr, args, num_args, ctx));
}

// A receiver reached through a pointer is modified through it, only for
// the call, after the other arguments are computed.
std::string receiver;
{
ScopedValue in_receiver(in_receiver_, true);
receiver = ConvertIRFragment(mc.receiver, expr, args, num_args, ctx);
receiver =
ConvertIRFragment(mc.receiver, bindings, expr, args, num_args, ctx);
}
if (pending_deref_.empty()) {
return receiver + ConvertIRFragment(mc.body, expr, args, num_args, ctx);
return receiver +
ConvertIRFragment(mc.body, bindings, expr, args, num_args, ctx);
}

auto ptr = pending_deref_.take();
auto body = ConvertIRFragment(mc.body, expr, args, num_args, ctx);
auto body = ConvertIRFragment(mc.body, bindings, expr, args, num_args, ctx);
MarkFresh();

return std::format("{}.with_mut(|__v: {}| __v{})", ptr, param_type, body);
Expand Down
11 changes: 6 additions & 5 deletions cpp2rust/converter/models/converter_refcount.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class ConverterRefCount final : public Converter {

std::string GetUnboxedTypeAsString(clang::QualType qual_type) override;

std::string GetUnboxedDefaultAsString(clang::QualType qual_type) override;

static void EmitMethodsOnPtr(std::string &out);

bool VisitRecordType(clang::RecordType *type) override;
Expand Down Expand Up @@ -319,11 +321,10 @@ class ConverterRefCount final : public Converter {
// converted.
bool in_receiver_ = false;

std::string
ConvertMappedMethodCall(clang::Expr *expr,
const TranslationRule::MethodCallFragment &mc,
clang::Expr **args, unsigned num_args,
TempMaterializationCtx *ctx) override;
std::string ConvertMappedMethodCall(
clang::Expr *expr, const TranslationRule::MethodCallFragment &mc,
llvm::ArrayRef<clang::TemplateArgument> bindings, clang::Expr **args,
unsigned num_args, TempMaterializationCtx *ctx) override;

private:
void SetUFCSReceiver(clang::Expr *base, bool is_arrow,
Expand Down
4 changes: 4 additions & 0 deletions cpp2rust/converter/rules/registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ void collectGenerics(const std::vector<TranslationRule::BodyFragment> &body,
std::get_if<TranslationRule::GenericFragment>(&fragment)) {
used.insert(generic->n);
}
if (auto generic =
std::get_if<TranslationRule::DefaultFragment>(&fragment)) {
used.insert(generic->n);
}
return false;
});
}
Expand Down
13 changes: 10 additions & 3 deletions cpp2rust/converter/translation_rule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ std::vector<BodyFragment> ParseBodyFragmentsJSON(const llvm::json::Array &arr) {
result.push_back(TextFragment{str->str()});
} else if (auto n = frag_obj->getInteger("generic")) {
result.push_back(GenericFragment{(unsigned)*n});
} else if (auto n = frag_obj->getInteger("default")) {
result.push_back(DefaultFragment{(unsigned)*n});
} else if (auto *ph = frag_obj->getObject("placeholder")) {
result.push_back(ParsePlaceholderFragmentJSON(*ph));
} else if (auto *mc = frag_obj->getObject("method_call")) {
Expand Down Expand Up @@ -232,6 +234,8 @@ void RefExprFragment::dump() const {

void GenericFragment::dump() const { log() << " generic: " << n << '\n'; }

void DefaultFragment::dump() const { log() << " default: " << n << '\n'; }

void TypeInfo::dump() const {
log() << type;
if (is_refcount_pointer)
Expand All @@ -247,7 +251,10 @@ void TypeRule::dump() const {
type_info.dump();
log() << '\n';
if (!initializer.empty()) {
log() << " init: " << initializer << '\n';
log() << " init:\n";
for (auto &frag : initializer) {
BodyFragmentDump(frag);
}
}
}

Expand Down Expand Up @@ -300,8 +307,8 @@ ExprRule ParseExprRuleJSON(const llvm::json::Object &obj) {

TypeRule ParseTypeRuleJSON(const llvm::json::Object &obj) {
TypeRule rule;
if (auto init = obj.getString("init"))
rule.initializer = init->str();
if (auto *init = obj.getArray("init"))
rule.initializer = ParseBodyFragmentsJSON(*init);
if (auto generic = obj.getInteger("generic"))
rule.generic = *generic;
rule.type_info = ParseTypeInfoJSON(obj);
Expand Down
17 changes: 12 additions & 5 deletions cpp2rust/converter/translation_rule.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ struct GenericFragment {
void dump() const;
};

struct DefaultFragment {
unsigned n;

void dump() const;
};

struct VaArgsFragment {
void dump() const;
};
Expand All @@ -52,10 +58,11 @@ struct InitFragment {
struct MethodCallFragment; // forward declaration
struct RefExprFragment;

using BodyFragment = std::variant<TextFragment, PlaceholderFragment,
GenericFragment, VaArgsFragment, InitFragment,
std::unique_ptr<MethodCallFragment>,
std::unique_ptr<RefExprFragment>>;
using BodyFragment =
std::variant<TextFragment, PlaceholderFragment, GenericFragment,
DefaultFragment, VaArgsFragment, InitFragment,
std::unique_ptr<MethodCallFragment>,
std::unique_ptr<RefExprFragment>>;

struct MethodCallFragment {
std::vector<BodyFragment> receiver;
Expand Down Expand Up @@ -101,7 +108,7 @@ struct ExprRule {
};

struct TypeRule {
std::string initializer; // Rust initializer expression
std::vector<BodyFragment> initializer; // Rust initializer expression
unsigned generic = 0;
TypeInfo type_info;

Expand Down
5 changes: 4 additions & 1 deletion rule-preprocessor/src/ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ impl FnIr {

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TypeIr {
pub init: String,
pub init: Vec<BodyFragment>,
#[serde(skip_serializing_if = "Option::is_none")]
pub generic: Option<i32>,
#[serde(flatten)]
Expand All @@ -161,6 +161,9 @@ pub enum BodyFragment {
Generic {
generic: i32,
},
Default {
default: i32,
},
MethodCall {
method_call: MethodCallInner,
},
Expand Down
Loading
Loading