Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
64ed654
Make receiver of vector objects a Ptr
lucic71 Oct 20, 2026
f41a62a
Update tests
lucic71 Oct 20, 2026
1db740f
Update tests
lucic71 Oct 20, 2026
c2c8bfe
Drop unneeded casts on ptr
lucic71 Oct 20, 2026
955cf95
Delete AsPointer for Vec
lucic71 Oct 20, 2026
8b002b1
Fix decay
lucic71 Oct 20, 2026
1e8d2c8
format
lucic71 Oct 20, 2026
ec164bc
Use field pointer instead of elem pointer
lucic71 Oct 20, 2026
a4f46de
Drop useless clones for receiver
lucic71 Oct 20, 2026
4ff48b9
Add rules for typedefs
lucic71 Oct 20, 2026
697482d
Add generic on types
lucic71 Oct 20, 2026
935a490
Update tests
lucic71 Oct 20, 2026
6f82e2b
Don't ask derives copy on canonical type
lucic71 Oct 20, 2026
e4cdfba
Instantiate generics for types in mapper queries
lucic71 Oct 20, 2026
2e52307
Match on typedefs instead of walking the typedef chain
lucic71 Oct 20, 2026
926f068
Don't visit system headers in address taken visitor
lucic71 Oct 20, 2026
e8fa99b
Add more types
lucic71 Oct 20, 2026
1c524ff
Abort on non-reference
lucic71 Oct 20, 2026
e54e02d
Update tests
lucic71 Oct 20, 2026
388c90f
Update tests
lucic71 Oct 20, 2026
213dc40
Peel user defiend typedefs
lucic71 Oct 20, 2026
9366436
Add more rules
lucic71 Oct 20, 2026
9710919
Add rule for add_lvalue_reference
lucic71 Oct 20, 2026
f07946d
Peel any type of sugar, not only typedef
lucic71 Oct 20, 2026
dd32055
ADd rule for iterator_traits reference
lucic71 Oct 20, 2026
1537fcc
Add rule for vector::reference
lucic71 Oct 20, 2026
2c69e22
Analyse non-builtin types as well
lucic71 Oct 20, 2026
2e93ecc
Add more rules
lucic71 Oct 20, 2026
cf4c220
Add key for typedef
lucic71 Oct 20, 2026
e73757d
Add rule for brotli
lucic71 Oct 20, 2026
de35ddc
Walk typedefs in IsUserDefinedDecl
lucic71 Oct 20, 2026
35eeb83
Instantiate generics in Match
lucic71 Oct 20, 2026
dbb1543
Merge branch 'vec-decay' into issue-535
lucic71 Oct 20, 2026
9bf41bd
Add rules for deque reference
lucic71 Oct 20, 2026
abd0dd3
Fix #549: std::swap and std::sort copy elements rather than moving th…
nunoplopes Oct 20, 2026
eb7a334
Update tests
lucic71 Oct 20, 2026
c327aed
Fix bindings order
lucic71 Oct 20, 2026
9901f98
Merge branch 'master' into issue-535
lucic71 Oct 20, 2026
accdc9d
Fix record derives copy
lucic71 Oct 20, 2026
2e4d19c
Update tests
lucic71 Oct 20, 2026
b7597b7
format
lucic71 Oct 20, 2026
81ad952
Merge branch 'master' into issue-535
lucic71 Oct 20, 2026
4697467
Update tests
lucic71 Oct 20, 2026
274417a
Merge branch 'master' into vec-decay
lucic71 Oct 20, 2026
90adcb7
Merge branch 'master' into vec-decay
lucic71 Oct 20, 2026
1ff1653
Update tests
lucic71 Oct 20, 2026
0f95023
Panic on large offsets
lucic71 Oct 20, 2026
3444e8e
Merge branch 'master' into vec-decay
lucic71 Oct 21, 2026
26dc5d8
Update tests
lucic71 Oct 21, 2026
44791e8
Merge branch 'vec-decay' into issue-535
lucic71 Oct 21, 2026
b028bef
Add more rules
lucic71 Oct 21, 2026
35243a2
Ignore internal private/protected typedefs
lucic71 Oct 21, 2026
f3d9ac6
Fix glibc private typedefs like __off_t
lucic71 Oct 21, 2026
c677560
Merge branch 'master' into issue-535
lucic71 Oct 21, 2026
3bfc015
Merge branch 'master' into issue-535
lucic71 Oct 21, 2026
f2d8c6d
Update tests
lucic71 Oct 21, 2026
66b7530
Add fs::string_type rule
lucic71 Oct 21, 2026
391eb18
Drop is zero check for initializer
lucic71 Oct 21, 2026
5f3e809
Update tests
lucic71 Oct 21, 2026
476344a
Add rules for private __off_t
lucic71 Oct 21, 2026
885f916
Add rules for private typedefs
lucic71 Oct 21, 2026
c5156ac
Only analyse user code in address taken visitor
lucic71 Oct 20, 2026
77b2e58
Merge branch 'master' into issue-535
lucic71 Oct 21, 2026
b818044
Insert rule for private typedef to avoid spelling them in rules
lucic71 Oct 21, 2026
5aa7977
Delete duplicated
lucic71 Oct 21, 2026
57f2cdc
format
lucic71 Oct 21, 2026
f54d1fe
Move filesystem rule in fs_path
lucic71 Oct 21, 2026
0c91bae
Refactor
lucic71 Oct 21, 2026
3ba89a5
Revert platform specific names
lucic71 Oct 21, 2026
b71a9c4
Format
lucic71 Oct 21, 2026
292faf3
Add TODO
lucic71 Oct 21, 2026
08a03d7
Trigger CI
lucic71 Oct 21, 2026
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
21 changes: 8 additions & 13 deletions cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -770,13 +770,13 @@ bool Converter::IsPassThroughRule(clang::Expr *expr) const {
rule->body[0]);
}

bool Converter::RecordDerivesCopy(const clang::RecordDecl *decl) {
bool Converter::RecordDerivesCopy(clang::QualType type) {
auto decl = type->getAsRecordDecl();
if (auto cxx = llvm::dyn_cast<clang::CXXRecordDecl>(decl);
cxx && cxx->isLambda()) {
return false;
}
if (auto rule =
RuleRegistry::Search(ctx_, ctx_.getCanonicalTagType(decl)).first) {
if (auto rule = RuleRegistry::Search(ctx_, type).first) {
auto &derives = rule->type_info.derives;
return std::find(derives.begin(), derives.end(), "Copy") != derives.end();
}
Expand Down Expand Up @@ -804,9 +804,9 @@ bool Converter::RecordHasCopyableFields(const clang::RecordDecl *decl) {
}

// Look recursively into fields that are RecordDecl, or arrays of them
if (auto field_record =
ctx_.getBaseElementType(f->getType())->getAsRecordDecl()) {
if (!RecordDerivesCopy(field_record)) {
if (auto field_type = ctx_.getBaseElementType(f->getType());
field_type->getAsRecordDecl()) {
if (!RecordDerivesCopy(field_type)) {
return false;
}
}
Expand Down Expand Up @@ -2304,11 +2304,6 @@ std::string Converter::getIntegerLiteral(clang::IntegerLiteral *expr,
auto type_as_string = GetUnsafeTypeAsString(ty);

if (ty->isFloatingType() || incl_type) {
if (value.isZero()) {
if (auto init = Mapper::MapInitializer(*this, ty); !init.empty()) {
return init;
}
}
return getTypedLiteral(num_as_string.c_str(), type_as_string);
}

Expand Down Expand Up @@ -4227,8 +4222,8 @@ std::string Converter::GetArrayDefaultAsString(clang::QualType qual_type) {
auto size_as_string = GetNumAsString(array_type->getSize());
auto element_type = array_type->getElementType();
auto element_type_as_string = GetDefaultAsString(element_type);
if (auto *rec = element_type->getAsRecordDecl()) {
if (!RecordDerivesCopy(rec)) {
if (element_type->getAsRecordDecl()) {
if (!RecordDerivesCopy(element_type)) {
return std::format("std::array::from_fn::<_, {}, _>(|_| {})",
size_as_string.c_str(), element_type_as_string);
}
Expand Down
6 changes: 3 additions & 3 deletions cpp2rust/converter/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -365,8 +365,8 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
if (ty->isBuiltinType() || ty->isEnumeralType()) {
return true;
}
if (auto *record = ty->getAsRecordDecl()) {
return RecordDerivesCopy(record);
if (ty->getAsRecordDecl()) {
return RecordDerivesCopy(ty);
}
return false;
}
Expand Down Expand Up @@ -791,7 +791,7 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {

virtual bool TypeDerivesDefault(clang::QualType qual_type);

bool RecordDerivesCopy(const clang::RecordDecl *decl);
bool RecordDerivesCopy(clang::QualType type);

bool IsPassThroughRule(clang::Expr *expr) const;

Expand Down
8 changes: 8 additions & 0 deletions cpp2rust/converter/converter_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,14 @@ bool IsUserDefinedDecl(const clang::Decl *decl) {
})) {
return false;
}
} else if (auto tag = llvm::dyn_cast<clang::TagDecl>(decl)) {
if (auto definition = tag->getDefinition()) {
decl = definition;
} else if (llvm::any_of(tag->redecls(), [&](auto redecl) {
return src_mgr.isInSystemHeader(redecl->getLocation());
})) {
return false;
}
}
auto src_loc = decl->getLocation();
if (auto *spec =
Expand Down
3 changes: 3 additions & 0 deletions cpp2rust/converter/models/boxed_vars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,9 @@ class AddressTakenVisitor
}

void AddressTaken(const clang::ValueDecl *decl) {
if (!IsUserDefinedDecl(decl)) {
return;
}
if (auto *var = clang::dyn_cast<clang::VarDecl>(decl);
var && CanUnbox(ctx_, var)) {
address_taken_.insert(var);
Expand Down
70 changes: 70 additions & 0 deletions cpp2rust/converter/rules/decls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include <optional>
#include <vector>

#include "converter/converter_lib.h"

namespace cpp2rust::RuleDecls {

const clang::Expr *SkipImplicit(const clang::Expr *expr) {
Expand Down Expand Up @@ -103,4 +105,72 @@ DeduceFromType(clang::Sema &sema, clang::TemplateParameterList *params,
return std::vector<clang::TemplateArgument>(deduced.begin(), deduced.end());
}

bool IsInternal(const clang::NamedDecl *decl) {
if (decl->getAccess() == clang::AS_private ||
decl->getAccess() == clang::AS_protected) {
return true;
}
auto &opts = decl->getASTContext().getLangOpts();
if (decl->isReserved(opts) != clang::ReservedIdentifierStatus::NotReserved) {
return true;
}
for (auto context = decl->getDeclContext(); context;
context = context->getParent()) {
if (context->isInlineNamespace()) {
continue;
}
auto named = llvm::dyn_cast<clang::NamedDecl>(context);
if (named && named->getIdentifier() &&
named->isReserved(opts) !=
clang::ReservedIdentifierStatus::NotReserved) {
return true;
}
}
return false;
}

clang::QualType PeelSugar(clang::ASTContext &ctx, clang::QualType type) {
while (!llvm::isa<clang::TypedefType, clang::PredefinedSugarType>(
type.getTypePtr()) &&
type != type.getSingleStepDesugaredType(ctx)) {
type = type.getSingleStepDesugaredType(ctx);
}
return type;
}

const clang::Type *GetSugar(clang::QualType type) {
if (auto typeof_type =
llvm::dyn_cast<clang::TypeOfExprType>(type.getTypePtr())) {
type = typeof_type->getUnderlyingExpr()->getType();
}
if (llvm::isa<clang::TypedefType, clang::PredefinedSugarType>(
type.getTypePtr())) {
return type.getTypePtr();
}
return nullptr;
}

clang::QualType SkipInternalTypedefs(clang::ASTContext &ctx,
clang::QualType use) {
auto cvr = use.getLocalCVRQualifiers();
auto type = PeelSugar(ctx, use);
while (auto typedef_type =
llvm::dyn_cast<clang::TypedefType>(type.getTypePtr())) {
auto decl = typedef_type->getDecl();
if (!IsInternal(decl) && !IsUserDefinedDecl(decl)) {
break;
}
type = PeelSugar(ctx, typedef_type->desugar());
cvr |= type.getLocalCVRQualifiers();
}
return type.withCVRQualifiers(cvr);
}

const clang::TypedefNameDecl *SpelledTypedef(clang::ASTContext &ctx,
clang::QualType use) {
auto sugar = GetSugar(PeelSugar(ctx, use));
auto typedef_type = llvm::dyn_cast_or_null<clang::TypedefType>(sugar);
return typedef_type ? typedef_type->getDecl() : nullptr;
}

} // namespace cpp2rust::RuleDecls
12 changes: 12 additions & 0 deletions cpp2rust/converter/rules/decls.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,16 @@ std::optional<std::vector<clang::TemplateArgument>>
DeduceFromType(clang::Sema &sema, clang::TemplateParameterList *params,
clang::QualType pattern, clang::QualType actual);

bool IsInternal(const clang::NamedDecl *decl);

clang::QualType PeelSugar(clang::ASTContext &ctx, clang::QualType type);

const clang::Type *GetSugar(clang::QualType type);

clang::QualType SkipInternalTypedefs(clang::ASTContext &ctx,
clang::QualType use);

const clang::TypedefNameDecl *SpelledTypedef(clang::ASTContext &ctx,
clang::QualType use);

} // namespace cpp2rust::RuleDecls
56 changes: 40 additions & 16 deletions cpp2rust/converter/rules/registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "converter/rules/registry.h"

#include <clang/AST/Attr.h>
#include <clang/AST/DeclCXX.h>
#include <clang/AST/DeclTemplate.h>
#include <clang/Basic/SourceManager.h>
Expand Down Expand Up @@ -273,22 +274,23 @@ struct TypeRuleMatch {

TypeRuleMatch findType(clang::QualType use) {
TypeRuleMatch best;
auto consider = [&](const RuleKeys::TypeKey &key) {
auto [begin, end] = types_.equal_range(key);
for (auto it = begin; it != end; ++it) {
auto match = AstMatcher::MatchType(*sema_, use, it->second.decl);
if (!match) {
continue;
}
if (best.rule_decl) {
if (match->depth > best.match.depth) {
auto &ctx = sema_->Context;
auto consider = [&](clang::QualType type, bool templates) {
for (auto key : RuleKeys::GetTypeKeys(ctx, type)) {
auto [begin, end] = types_.equal_range(key);
for (auto it = begin; it != end; ++it) {
if (!templates && llvm::isa<clang::TemplateDecl>(it->second.decl)) {
continue;
}
if (match->depth == best.match.depth) {
auto match = AstMatcher::MatchType(*sema_, type, it->second.decl);
if (!match) {
continue;
}
if (best.rule_decl) {
auto better = AstMatcher::MoreSpecializedType(*sema_, it->second.decl,
best.rule_decl->decl);
if (!better) {
use.dump(llvm::errs(), sema_->Context);
type.dump(llvm::errs(), ctx);
it->second.decl->dump(llvm::errs());
best.rule_decl->decl->dump(llvm::errs());
llvm::report_fatal_error(
Expand All @@ -298,12 +300,31 @@ TypeRuleMatch findType(clang::QualType use) {
continue;
}
}
best = {&it->second, *std::move(match)};
}
best = {&it->second, *std::move(match)};
}
};
for (auto key : RuleKeys::GetTypeKeys(sema_->Context, use)) {
consider(key);
auto skipped = RuleDecls::SkipInternalTypedefs(ctx, use);
if (RuleDecls::SpelledTypedef(ctx, skipped) !=
RuleDecls::SpelledTypedef(ctx, use)) {
consider(use, /*templates=*/false);
if (best.rule_decl) {
return best;
}
}
use = skipped;
if (auto tag = use->getAsTagDecl();
tag &&
(IsUserDefinedDecl(tag) || tag->hasAttr<clang::TransparentUnionAttr>())) {
return best;
}
consider(use, /*templates=*/true);
if (!best.rule_decl) {
auto spelled = RuleDecls::SpelledTypedef(ctx, use);
if (spelled && !IsUserDefinedDecl(spelled)) {
use.dump(llvm::errs(), ctx);
llvm::report_fatal_error("typedef has no type rule");
}
}
return best;
}
Expand Down Expand Up @@ -401,8 +422,11 @@ Matcher::Match<TranslationRule::TypeRule> Search(clang::ASTContext &ctx,
if (!match.rule_decl) {
return {};
}
return {&match.rule_decl->rule,
getBindings(match.rule_decl->decl, match.match.args)};
auto bindings = getBindings(match.rule_decl->decl, match.match.args);
if (auto generic = match.rule_decl->rule.generic) {
return Search(ctx, bindings.at(generic - 1).getAsType());
}
return {&match.rule_decl->rule, std::move(bindings)};
}

const TranslationRule::ExprRule *GetExprRule(clang::ASTContext &ctx,
Expand Down
23 changes: 11 additions & 12 deletions cpp2rust/converter/rules/rule_keys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ const clang::Decl *getParent(clang::QualType type) {
llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(record)) {
return spec->getSpecializedTemplate()->getCanonicalDecl();
}
if (auto tmpl = record->getDescribedClassTemplate()) {
return tmpl->getCanonicalDecl();
}
return record->getCanonicalDecl();
}

Expand Down Expand Up @@ -277,21 +280,17 @@ std::vector<TypeKey> GetTypeKeys(clang::ASTContext &ctx, clang::QualType use) {
record && !use->isDependentType() && !IsUserDefinedDecl(record)) {
keys.push_back(kAnyClass);
}
for (auto type = use;; type = type.getSingleStepDesugaredType(ctx)) {
if (auto typedef_type =
llvm::dyn_cast<clang::TypedefType>(type.getTypePtr())) {
if (auto owner = llvm::dyn_cast<clang::CXXRecordDecl>(
typedef_type->getDecl()->getDeclContext())) {
auto key = GetTypeKey(ctx.getCanonicalTagType(owner));
if (key && !llvm::is_contained(keys, *key)) {
keys.push_back(*key);
}
if (auto typedef_type =
llvm::dyn_cast<clang::TypedefType>(use.getTypePtr())) {
if (auto owner = llvm::dyn_cast<clang::CXXRecordDecl>(
typedef_type->getDecl()->getDeclContext())) {
auto key = GetTypeKey(ctx.getCanonicalTagType(owner));
if (key && !llvm::is_contained(keys, *key)) {
keys.push_back(*key);
}
}
if (type.getSingleStepDesugaredType(ctx) == type) {
return keys;
}
}
return keys;
}

std::optional<ExprKey> GetDeclKey(const clang::NamedDecl *decl) {
Expand Down
Loading
Loading