diff --git a/CMakeLists.txt b/CMakeLists.txt index 933b9a235..7ff650e9a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -179,6 +179,9 @@ file(GLOB_RECURSE rule_preprocessor_sources file(GLOB_RECURSE libcc2rs_sources CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/libcc2rs/src/*.rs ${PROJECT_SOURCE_DIR}/libcc2rs-macros/src/*.rs) +file(GLOB rule_shim_sources CONFIGURE_DEPENDS + ${PROJECT_SOURCE_DIR}/rules/*/shim.rs) +list(APPEND libcc2rs_sources ${rule_shim_sources}) list(APPEND libcc2rs_sources ${PROJECT_SOURCE_DIR}/libcc2rs/Cargo.toml ${PROJECT_SOURCE_DIR}/libcc2rs-macros/Cargo.toml) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index fdc619bb9..dae3b5916 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -793,21 +793,6 @@ bool Converter::RecordHasCopyableFields(const clang::RecordDecl *decl) { return false; } for (auto f : decl->fields()) { - // Records that contain std::vector, std::array, std::string or anything - // that is translated to Vec<>, do not derive Copy - auto mapped = Mapper::Map(*this, f->getType()); - if (mapped.starts_with("Vec<")) { - return false; - } - - if (IsUniquePtr(f->getType())) { - return false; - } - - if (mapped.starts_with("BTreeMap<")) { - return false; - } - if (auto ptr_ty = f->getType()->getAs()) { if (ptr_ty->getPointeeType()->isFunctionType()) { if (!FunctionPointerImplementsCopy()) { @@ -1575,7 +1560,7 @@ bool Converter::VisitCXXForRangeStmtMap(clang::CXXForRangeStmt *stmt) { StrCat("'loop_:"); auto map_type = Mapper::Map(*this, stmt->getRangeInit()->getType()); StrCat(keyword::kFor, GetNamedDeclAsString(begin), keyword::kIn, - "UnsafeMapIterator::begin(&"); + "UnsafeMap::range(&"); Convert(stmt->getRangeInit()); StrCat(std::format(" as *const {})", map_type)); { @@ -3362,9 +3347,6 @@ bool Converter::ConvertCXXOperatorCallExpr(clang::CXXOperatorCallExpr *expr) { case clang::OverloadedOperatorKind::OO_Arrow: if (IsUniquePtr(expr->getArg(0)->getType())) { ConvertUniquePtrDeref(expr); - } else if (GetStrongestIteratorCategory(ctx_, expr->getArg(0)->getType()) == - IteratorCategory::Bidirectional) { - Convert(expr->getArg(0)); } else if (expr->getOperator() == clang::OverloadedOperatorKind::OO_Star) { PushParen paren(*this); StrCat(token::kStar); @@ -3914,8 +3896,6 @@ void Converter::ConvertCXXConstructExprArgs(clang::CXXConstructExpr *expr) { } bool Converter::VisitCXXConstructExpr(clang::CXXConstructExpr *expr) { - PushSuppressIteratorClone push(*this, expr); - if (expr->isElidable()) { Convert(expr->getArg(0)); return false; @@ -3938,11 +3918,9 @@ bool Converter::VisitCXXConstructExpr(clang::CXXConstructExpr *expr) { return false; } if (IsPassThroughConstructor(ctor)) { - // Take suppress before recursing into the child. - bool suppress = PushSuppressIteratorClone::take(*this); Convert(expr->getArg(0)); if ((ctor->isCopyConstructor() || IsDefaultedMoveConstructor(ctor)) && - !suppress && !TypeIsCopyable(expr->getType())) { + !TypeIsCopyable(expr->getType())) { StrCat(".clone()"); SetFreshType(expr->getType()); } @@ -5452,14 +5430,6 @@ void Converter::ConvertConstructFromArgs(clang::QualType type, std::string Converter::AccessLValueObject(clang::MemberExpr *member) { auto *object = member->getBase(); auto type = object->getType(); - if (member->isArrow()) { - auto *op = - clang::dyn_cast(object->IgnoreImplicit()); - if (op && GetStrongestIteratorCategory(ctx_, op->getArg(0)->getType()) == - IteratorCategory::Bidirectional) { - return ToString(object); - } - } if (type->isPointerType() || (IsReferenceType(object) && clang::isa(object))) { return std::format("({}{})", GetPointerDerefPrefix(type->getPointeeType()), diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index f79c57995..201018834 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -841,7 +841,6 @@ class Converter : public clang::RecursiveASTVisitor { std::string ufcs_receiver_; bool in_const_initializer_ = false; std::optional autoref_mut_; - bool suppress_iterator_clone_ = false; struct PushExplicitAutoref { Converter &c; @@ -853,41 +852,6 @@ class Converter : public clang::RecursiveASTVisitor { ~PushExplicitAutoref() { c.autoref_mut_ = prev; } }; - struct PushSuppressIteratorClone { - Converter &c; - bool prev; - PushSuppressIteratorClone(Converter &c, clang::CXXConstructExpr *expr) - : c(c), prev(c.suppress_iterator_clone_) { - auto *ctor = expr->getConstructor(); - if (!ctor->isCopyOrMoveConstructor() && - ctor->isConvertingConstructor(/*AllowExplicit=*/false) && - ctor->getNumParams() == 1 && IsIteratorType(expr->getType())) { - c.suppress_iterator_clone_ = true; - } - } - ~PushSuppressIteratorClone() { c.suppress_iterator_clone_ = prev; } - PushSuppressIteratorClone(const PushSuppressIteratorClone &) = delete; - PushSuppressIteratorClone & - operator=(const PushSuppressIteratorClone &) = delete; - - static bool take(Converter &c) { - return std::exchange(c.suppress_iterator_clone_, false); - } - - private: - static bool IsIteratorType(clang::QualType qt) { - if (auto *record = qt->getAsCXXRecordDecl()) { - for (auto *d : record->decls()) { - if (auto *tnd = llvm::dyn_cast(d)) { - if (tnd->getName() == "iterator_category") - return true; - } - } - } - return false; - } - }; - struct PushConstInitializer { Converter &c; bool prev; diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 0216b18c7..c516fefe5 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -1892,7 +1892,7 @@ clang::Expr *GetCallee(clang::CallExpr *expr) { } bool HasReceiver(clang::Expr *expr) { - if (clang::isa(expr)) + if (clang::isa(expr)) return true; if (auto *opcall = clang::dyn_cast(expr)) { if (auto *callee = opcall->getCalleeDecl()) { @@ -1920,26 +1920,6 @@ std::optional GetParamImplicitConvertTarget(clang::Expr *expr, return fn->getParamDecl(param_idx)->getType().getNonReferenceType(); } -std::optional -GetStrongestIteratorCategory(clang::ASTContext &ctx, clang::QualType type) { - type = type.getNonReferenceType().getUnqualifiedType(); - if (!Mapper::Contains(ctx, type)) { - return std::nullopt; - } - if (RuleRegistry::MapsToRefcountPointer(ctx, type)) { - return IteratorCategory::Contiguous; - } - auto mapped = Mapper::Map(ctx, type); - if (mapped.empty()) { - return std::nullopt; - } - if (mapped.starts_with("RefcountMapIter<") || - mapped.starts_with("UnsafeMapIterator<")) { - return IteratorCategory::Bidirectional; - } - return std::nullopt; -} - std::string GetClassName(clang::QualType type) { if (auto *record = type->getAsCXXRecordDecl()) return record->getQualifiedNameAsString(); diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index 19f35152b..f8511750d 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -28,17 +28,6 @@ class Sema; namespace cpp2rust { -// Order matters: each category is a superset of the previous one. -// Use >= to check "at least this capable". -enum class IteratorCategory { - Forward, - Bidirectional, - RandomAccess, - Contiguous, -}; - -std::optional -GetStrongestIteratorCategory(clang::ASTContext &ctx, clang::QualType type); bool IsBuiltinConstantP(const clang::Expr *expr); bool IsGlobalVar(const clang::VarDecl *decl); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 1bd1af1a9..d2854addd 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -97,8 +97,8 @@ static bool IsFieldOfVectorElem(const clang::MemberExpr *expr) { } static bool IsPointerType(clang::ASTContext &ctx, clang::QualType type) { - return type->isPointerType() || GetStrongestIteratorCategory(ctx, type) == - IteratorCategory::Contiguous; + return type->isPointerType() || + RuleRegistry::MapsToRefcountPointer(ctx, type); } void ConverterRefCount::PendingDeref::set(std::string str, bool fresh) { @@ -2279,7 +2279,7 @@ bool ConverterRefCount::VisitCXXForRangeStmtMap(clang::CXXForRangeStmt *stmt) { auto begin_name = GetNamedDeclAsString(begin); StrCat("'loop_:"); - StrCat(keyword::kFor, begin_name, keyword::kIn, "RefcountMapIter::begin(", + StrCat(keyword::kFor, begin_name, keyword::kIn, "Map::range(", ConvertObject(stmt->getRangeInit()), ')'); PushBrace brace(*this); @@ -2375,7 +2375,6 @@ bool ConverterRefCount::VisitCXXConstructExpr(clang::CXXConstructExpr *expr) { getConversionKind() != ConversionKind::Unboxed; PushConversionKind push(*this, boxed_array ? ConversionKind::Pointee : ConversionKind::Unboxed); - PushSuppressIteratorClone push_suppress(*this, expr); if (auto str = GetMappedAsString(expr, expr->getArgs(), expr->getNumArgs()); !str.empty()) { @@ -2408,9 +2407,7 @@ bool ConverterRefCount::VisitCXXConstructExpr(clang::CXXConstructExpr *expr) { if (ctor->isCopyOrMoveConstructor() && !IsConvertibleCopyOrMoveConstructor(ctor)) { - StrCat(PushSuppressIteratorClone::take(*this) - ? ConvertRValue(expr->getArg(0)) - : ConvertFreshRValue(expr->getArg(0))); + StrCat(ConvertFreshRValue(expr->getArg(0))); return false; } @@ -2848,12 +2845,6 @@ bool ConverterRefCount::ConvertCXXOperatorCallExpr( break; } - if (GetStrongestIteratorCategory(ctx_, expr->getArg(0)->getType()) == - IteratorCategory::Bidirectional) { - Convert(expr->getArg(0)); - break; - } - { bool deref = !isAddrOf(); PushParen paren(*this, deref); @@ -3314,7 +3305,8 @@ void ConverterRefCount::ConvertArrow(clang::Expr *expr) { bool is_overloaded_arrow = op && op->getOperator() == clang::OverloadedOperatorKind::OO_Arrow; - if (!is_overloaded_arrow || IsUserOperatorCall(op)) { + if (!is_overloaded_arrow || IsUserOperatorCall(op) || + RuleRegistry::ReturnsPointer(ctx_, expr)) { auto pointee_type = expr->getType()->getPointeeType(); // Virtual methods, which take &mut self, are called through PtrDyn. if (auto *record = pointee_type->getAsRecordDecl(); @@ -3333,12 +3325,6 @@ void ConverterRefCount::ConvertArrow(clang::Expr *expr) { return; } - if (GetStrongestIteratorCategory(ctx_, op->getArg(0)->getType()) == - IteratorCategory::Bidirectional) { - Convert(op->getArg(0)); - return; - } - Convert(expr); } @@ -3348,12 +3334,6 @@ std::string ConverterRefCount::AccessLValueObject(clang::MemberExpr *member) { bool is_mut = method && !method->isConst(); if (member->isArrow()) { - auto *op = - clang::dyn_cast(object->IgnoreImplicit()); - if (op && GetStrongestIteratorCategory(ctx_, op->getArg(0)->getType()) == - IteratorCategory::Bidirectional) { - return ConvertRValue(op->getArg(0)); - } auto str = is_mut ? ConvertLValue(object) : ConvertRValue(object); auto pointee_type = object->getType()->getPointeeType(); return DerefPtrExpr(str, pointee_type); diff --git a/cpp2rust/converter/rules/decls.cpp b/cpp2rust/converter/rules/decls.cpp index c621e1d70..90dac3789 100644 --- a/cpp2rust/converter/rules/decls.cpp +++ b/cpp2rust/converter/rules/decls.cpp @@ -77,30 +77,6 @@ const clang::Expr *GetMacroMemberBase(const clang::SourceManager &sm, } } -clang::QualType EnableIfSameType(const clang::Decl *rule) { - auto tmpl = llvm::dyn_cast(rule); - if (!tmpl) { - return {}; - } - for (auto param : *tmpl->getTemplateParameters()) { - auto type_param = llvm::dyn_cast(param); - if (!type_param || type_param->getIdentifier() || - !type_param->hasDefaultArgument()) { - continue; - } - auto same = type_param->getDefaultArgument() - .getArgument() - .getAsType() - ->getAs(); - if (!same || !same->isTypeAlias() || - same->getTemplateName().getAsTemplateDecl()->getName() != "SameAs") { - continue; - } - return same->template_arguments()[1].getAsType(); - } - return {}; -} - std::optional> DeduceFromType(clang::Sema &sema, clang::TemplateParameterList *params, clang::QualType pattern, clang::QualType actual) { diff --git a/cpp2rust/converter/rules/decls.h b/cpp2rust/converter/rules/decls.h index 6c97da7c8..2ab5a2729 100644 --- a/cpp2rust/converter/rules/decls.h +++ b/cpp2rust/converter/rules/decls.h @@ -42,8 +42,6 @@ const clang::Expr *GetReturned(const clang::FunctionDecl *rule); const clang::Expr *GetMacroMemberBase(const clang::SourceManager &sm, const clang::MemberExpr *member); -clang::QualType EnableIfSameType(const clang::Decl *rule); - std::optional> DeduceFromType(clang::Sema &sema, clang::TemplateParameterList *params, clang::QualType pattern, clang::QualType actual); diff --git a/cpp2rust/converter/rules/expr_matcher.cpp b/cpp2rust/converter/rules/expr_matcher.cpp index fd7860db2..2eb8c9b19 100644 --- a/cpp2rust/converter/rules/expr_matcher.cpp +++ b/cpp2rust/converter/rules/expr_matcher.cpp @@ -155,10 +155,6 @@ std::vector getOperands(clang::ASTContext &ctx, auto base = const_cast(macro_base ? macro_base : member->getBase()) ->IgnoreParenImpCasts(); - if (auto arrow = llvm::dyn_cast(base); - arrow && arrow->getOperator() == clang::OO_Arrow) { - base = arrow->getArg(0); - } operands.push_back(getObject(ctx, base)); } while (!operands.empty() && diff --git a/cpp2rust/converter/rules/registry.cpp b/cpp2rust/converter/rules/registry.cpp index c4aabadcc..fd19c1722 100644 --- a/cpp2rust/converter/rules/registry.cpp +++ b/cpp2rust/converter/rules/registry.cpp @@ -22,6 +22,7 @@ #include #include "converter/converter_lib.h" +#include "converter/rules/decls.h" #include "converter/rules/expr_matcher.h" #include "converter/rules/rule_keys.h" #include "converter/rules/rules_loader.h" @@ -83,6 +84,40 @@ clang::QualType getInitPattern(const clang::FunctionDecl *rule) { return alias->template_arguments()[0].getAsType(); } +void collectGenerics(const std::vector &body, + std::unordered_set &used) { + for (const auto &fragment : body) { + if (auto generic = + std::get_if(&fragment)) { + used.insert(generic->n); + } else if (auto call = std::get_if< + std::unique_ptr>( + &fragment)) { + collectGenerics((*call)->receiver, used); + collectGenerics((*call)->body, used); + } + } +} + +void collectGenerics(llvm::StringRef type, std::unordered_set &used) { + auto is_ident = [](char c) { return llvm::isAlnum(c) || c == '_'; }; + for (size_t i = 0; i < type.size(); ++i) { + if (type[i] != 'T' || (i > 0 && is_ident(type[i - 1]))) { + continue; + } + size_t end = i + 1; + while (end < type.size() && llvm::isDigit(type[end])) { + ++end; + } + unsigned n = 0; + if (end > i + 1 && (end == type.size() || !is_ident(type[end])) && + !type.slice(i + 1, end).getAsInteger(10, n)) { + used.insert(n); + } + i = end - 1; + } +} + void checkGenerics(const std::string &dir, const std::string &name, const clang::FunctionDecl *decl, const TranslationRule::ExprRule &rule) { @@ -92,10 +127,16 @@ void checkGenerics(const std::string &dir, const std::string &name, declared.insert(param->getName().str()); } } - for (unsigned i = 1; i <= rule.generics.size(); ++i) { + std::unordered_set used; + collectGenerics(rule.body, used); + collectGenerics(rule.return_type.type, used); + for (const auto ¶m : rule.params) { + collectGenerics(param.type, used); + } + for (unsigned i : used) { if (!declared.contains(std::format("T{}", i))) { llvm::errs() << dir << "::" << name << ": generic T" << i - << " declared but missing from src\n"; + << " used by the target but missing from src\n"; llvm::report_fatal_error("Absent generic from src"); } } @@ -211,6 +252,13 @@ ExprMatch findExpr(const clang::Expr *use) { if (auto member = std::get_if(&*key)) { consider(RuleKeys::Unqualified{member->name}); } + if (std::holds_alternative(*key)) { + auto type = RuleDecls::SkipImplicit(use)->getType(); + if (auto record = type.getCanonicalType()->getAsCXXRecordDecl(); + record && !type->isDependentType() && !IsUserDefinedDecl(record)) { + consider(RuleKeys::kAnyConstructor); + } + } return best; } @@ -236,6 +284,9 @@ TypeRuleMatch findType(clang::QualType use) { auto better = AstMatcher::MoreSpecializedType(*sema_, it->second.decl, best.rule_decl->decl); if (!better) { + use.dump(llvm::errs(), sema_->Context); + it->second.decl->dump(llvm::errs()); + best.rule_decl->decl->dump(llvm::errs()); llvm::report_fatal_error( "type matches several rules, none more specialized"); } diff --git a/cpp2rust/converter/rules/rule_keys.cpp b/cpp2rust/converter/rules/rule_keys.cpp index 3ad820322..98e263396 100644 --- a/cpp2rust/converter/rules/rule_keys.cpp +++ b/cpp2rust/converter/rules/rule_keys.cpp @@ -15,6 +15,7 @@ #include #include +#include "converter/converter_lib.h" #include "converter/rules/decls.h" namespace cpp2rust::RuleKeys { @@ -205,6 +206,12 @@ std::vector GetExprKeys(clang::ASTContext &ctx, llvm::dyn_cast(returned)) { std::vector keys; for (auto type : resolveMemberType(construct->getTypeAsWritten())) { + if (type->getAs()) { + if (!llvm::is_contained(keys, ExprKey{kAnyConstructor})) { + keys.push_back(kAnyConstructor); + } + continue; + } auto key = getConstructorKey(getParent(type)); assert(key && "expression rule has no key"); if (!llvm::is_contained(keys, *key)) { @@ -240,18 +247,7 @@ std::vector GetTypeKeys(const clang::NamedDecl *rule) { assert(alias && "type rule is not an alias"); auto pattern = alias->getUnderlyingType(); if (pattern->getAs()) { - pattern = RuleDecls::EnableIfSameType(rule); - assert(!pattern.isNull() && - "type rule matching any type must be constrained by enable_if"); - std::vector keys; - for (auto type : resolveMemberType(pattern)) { - auto key = GetTypeKey(type); - assert(key && "type rule has no key"); - if (!llvm::is_contained(keys, *key)) { - keys.push_back(*key); - } - } - return keys; + return {kAnyClass}; } if (auto member = pattern->getAs()) { auto qualifier = member->getQualifier().getAsType(); @@ -270,6 +266,10 @@ std::vector GetTypeKeys(clang::ASTContext &ctx, clang::QualType use) { if (auto key = GetTypeKey(use)) { keys.push_back(*key); } + if (auto record = use.getCanonicalType()->getAsCXXRecordDecl(); + record && !use->isDependentType() && !IsUserDefinedDecl(record)) { + keys.push_back(kAnyClass); + } for (auto type = use;; type = type.getSingleStepDesugaredType(ctx)) { if (auto typedef_type = llvm::dyn_cast(type.getTypePtr())) { diff --git a/cpp2rust/converter/rules/rule_keys.h b/cpp2rust/converter/rules/rule_keys.h index 7056a51ed..6eec76ab3 100644 --- a/cpp2rust/converter/rules/rule_keys.h +++ b/cpp2rust/converter/rules/rule_keys.h @@ -39,6 +39,9 @@ using ExprKey = std::variant; using TypeKey = std::variant; +inline const TypeKey kAnyClass = static_cast(nullptr); +inline const Constructor kAnyConstructor{nullptr}; + std::optional GetExprKey(clang::ASTContext &ctx, const clang::Expr *use); diff --git a/cpp2rust/converter/rules/rules_loader.cpp b/cpp2rust/converter/rules/rules_loader.cpp index 73f5c1bfe..4ae9bd661 100644 --- a/cpp2rust/converter/rules/rules_loader.cpp +++ b/cpp2rust/converter/rules/rules_loader.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -203,6 +204,7 @@ class RuleUsageCollector AddTemplateArgs(spec->getTemplateArgs().asArray()); } AddSpecialMembers(record); + AddIterator(type, record); } return; } @@ -226,6 +228,46 @@ class RuleUsageCollector } } + void AddIterator(clang::QualType type, const clang::CXXRecordDecl *record) { + auto *std_namespace = sema_.getStdNamespace(); + if (!std_namespace || + !ctx_.getSourceManager().isInSystemHeader(record->getLocation())) { + return; + } + clang::ClassTemplateDecl *traits = nullptr; + for (auto *decl : + std_namespace->lookup(&ctx_.Idents.get("iterator_traits"))) { + if ((traits = llvm::dyn_cast(decl))) { + break; + } + } + if (!traits) { + return; + } + auto loc = record->getLocation(); + RuleDecls::Trial trial(sema_); + clang::TemplateArgumentListInfo args(loc, loc); + args.addArgument( + clang::TemplateArgumentLoc(clang::TemplateArgument(type), + ctx_.getTrivialTypeSourceInfo(type, loc))); + auto instance = sema_.CheckTemplateIdType( + clang::ElaboratedTypeKeyword::None, clang::TemplateName(traits), loc, + args, /*Scope=*/nullptr, /*ForNestedNameSpecifier=*/false); + if (instance.isNull() || !sema_.isCompleteType(loc, instance) || + trial.failed()) { + return; + } + auto *instance_record = instance->getAsCXXRecordDecl(); + if (!instance_record) { + return; + } + clang::LookupResult category(sema_, &ctx_.Idents.get("iterator_category"), + loc, clang::Sema::LookupMemberName); + if (sema_.LookupQualifiedName(category, instance_record)) { + AddKey(kAnyIteratorKey); + } + } + void AddTemplateArgs(llvm::ArrayRef args) { for (const auto &arg : args) { switch (arg.getKind()) { @@ -310,7 +352,9 @@ std::string BuildRulesEpilogue(const std::unordered_set &keys, out += "namespace cpp2rust_rules {\n" + common->str() + "}\n"; } auto rules = index.getObject("rules"); - for (const auto &key : keys) { + std::vector candidates(keys.begin(), keys.end()); + candidates.push_back(kAnyClassKey); + for (const auto &key : candidates) { auto entries = rules->getArray(key); if (!entries) { continue; diff --git a/cpp2rust/converter/rules/rules_loader.h b/cpp2rust/converter/rules/rules_loader.h index 52919d519..75dbf6915 100644 --- a/cpp2rust/converter/rules/rules_loader.h +++ b/cpp2rust/converter/rules/rules_loader.h @@ -19,6 +19,10 @@ namespace cpp2rust::RulesLoader { inline constexpr const char *kPragmaName = "cpp2rust_rules"; +inline constexpr const char *kAnyClassKey = "*"; + +inline constexpr const char *kAnyIteratorKey = "std/iterator_traits"; + std::string ClassKey(const clang::NamedDecl *decl); std::string MemberName(clang::DeclarationName name); diff --git a/cpp2rust/rule_preprocessing/cpp_rule_indexer.cpp b/cpp2rust/rule_preprocessing/cpp_rule_indexer.cpp index 2478d6f2c..122f19d04 100644 --- a/cpp2rust/rule_preprocessing/cpp_rule_indexer.cpp +++ b/cpp2rust/rule_preprocessing/cpp_rule_indexer.cpp @@ -26,7 +26,6 @@ #include #include "compat/platform_flags.h" -#include "converter/rules/decls.h" #include "converter/rules/rules_loader.h" namespace fs = std::filesystem; @@ -134,11 +133,6 @@ std::string ClassOfParameters(const clang::Decl *rule) { return {}; } -std::string ClassOfEnableIf(const clang::Decl *rule) { - auto same = RuleDecls::EnableIfSameType(rule); - return same.isNull() ? std::string() : ClassOf(same); -} - const clang::Expr *RuleExpr(const clang::Decl *decl) { if (auto var = llvm::dyn_cast(decl)) { return var->getInit(); @@ -266,8 +260,9 @@ void IndexRuleFile(clang::ASTContext &ctx, const std::string &dir_name, if (key.empty()) { key = ClassOfParameters(decl); } - if (key.empty()) { - key = ClassOfEnableIf(decl); + bool any_class = key.empty() && llvm::isa(decl); + if (any_class) { + key = RulesLoader::kAnyClassKey; } if (key.empty()) { llvm::errs() << "ERROR: cannot derive the key of rule '" << name @@ -277,7 +272,10 @@ void IndexRuleFile(clang::ASTContext &ctx, const std::string &dir_name, auto range = clang::tooling::getExtendedRange(*decl, clang::tok::semi, ctx); auto text = clang::tooling::getText(range, ctx).str() + '\n'; llvm::json::Object rule{{"dir", dir_name}, {"name", name}, {"text", text}}; - if (auto required = RequiredClasses(decl, alias); !required.empty()) { + if (any_class) { + rule["requires"] = llvm::json::Array{RulesLoader::kAnyIteratorKey}; + } else if (auto required = RequiredClasses(decl, alias); + !required.empty()) { rule["requires"] = llvm::json::Array(required); } AddRule(rules, key, std::move(rule)); diff --git a/libcc2rs/src/iterators.rs b/libcc2rs/src/iterators.rs index 58fb7a6da..81e42da7e 100644 --- a/libcc2rs/src/iterators.rs +++ b/libcc2rs/src/iterators.rs @@ -1,215 +1,7 @@ // Copyright (c) 2022-present INESC-ID. // Distributed under the MIT license that can be found in the LICENSE file. -use crate::{AsPointer, CChar, PostfixDec, PostfixInc, PrefixDec, PrefixInc, Ptr, Value}; -use std::collections::BTreeMap; -use std::ops::Bound; - -pub trait MapAccess: Clone + Default { - type Key: Ord + Clone; - type Value; - fn with(&self, f: impl FnOnce(&BTreeMap) -> R) -> R; - fn with_mut(&self, f: impl FnOnce(&mut BTreeMap) -> R) -> R; -} - -impl MapAccess for Ptr> { - type Key = K; - type Value = V; - - fn with(&self, f: impl FnOnce(&BTreeMap) -> R) -> R { - Ptr::with(self, f) - } - - fn with_mut(&self, f: impl FnOnce(&mut BTreeMap) -> R) -> R { - Ptr::with_mut(self, f) - } -} - -impl MapAccess for *const BTreeMap { - type Key = K; - type Value = V; - - fn with(&self, f: impl FnOnce(&BTreeMap) -> R) -> R { - unsafe { f(&**self) } - } - - fn with_mut(&self, f: impl FnOnce(&mut BTreeMap) -> R) -> R { - unsafe { f(&mut *(*self as *mut BTreeMap)) } - } -} - -pub struct MapIter { - map: MapRef, - key: Option, -} - -pub type RefcountMapIter = MapIter, Value)>>>>; -pub type UnsafeMapIterator = MapIter>>; - -impl Clone for MapIter { - fn clone(&self) -> Self { - Self { - map: self.map.clone(), - key: self.key.clone(), - } - } -} - -impl PartialEq for MapIter { - fn eq(&self, other: &Self) -> bool { - self.key == other.key - } -} - -impl> MapIter { - pub fn null() -> Self { - Self { - map: Default::default(), - key: None, - } - } - - pub fn begin(map: MapRef) -> Self { - let first_key = map.with(|m| m.keys().next().cloned()); - Self { - map, - key: first_key, - } - } - - pub fn end(map: MapRef) -> Self { - Self { map, key: None } - } - - pub fn find_key(map: MapRef, key: &K) -> Self { - if map.with(|m| m.contains_key(key)) { - Self { - map, - key: Some(key.clone()), - } - } else { - Self::end(map) - } - } - - pub fn is_end(&self) -> bool { - self.key.is_none() - } - - pub fn key(&self) -> &Option { - &self.key - } - - pub fn inc(&mut self) { - self.key = match &self.key { - Some(k) => self.map.with(|map| { - map.range((Bound::Excluded(k), Bound::Unbounded)) - .next() - .map(|(k, _)| k.clone()) - }), - None => panic!("ub: increment past end"), - }; - } - - pub fn dec(&mut self) { - self.key = match &self.key { - Some(k) => self.map.with(|map| { - map.range((Bound::Unbounded, Bound::Excluded(k))) - .next_back() - .map(|(k, _)| k.clone()) - }), - None => self.map.with(|map| map.keys().next_back().cloned()), - }; - } - - pub fn erase(map: MapRef, iter: &Self) -> Self { - let key = iter - .key - .as_ref() - .expect("ub: erase of end iterator") - .clone(); - let next_key = map.with(|m| { - m.range((Bound::Excluded(&key), Bound::Unbounded)) - .next() - .map(|(k, _)| k.clone()) - }); - map.with_mut(|m| m.remove(&key)); - Self { map, key: next_key } - } -} - -pub trait MapIterator { - type Entry; - fn deref(&self) -> Self::Entry; -} - -impl MapIterator for RefcountMapIter { - type Entry = Ptr<(Value, Value)>; - - fn deref(&self) -> Ptr<(Value, Value)> { - let key = self.key.as_ref().expect("ub: dereference of end iterator"); - self.map - .with(|m| m.get(key).expect("ub: key not found in map").as_pointer()) - } -} - -impl MapIterator for UnsafeMapIterator { - type Entry = *mut (K, V); - - fn deref(&self) -> *mut (K, V) { - unsafe { - let map_mut = self.map as *mut BTreeMap>; - let key = self.key.as_ref().expect("ub: dereference of end iterator"); - (*map_mut) - .get_mut(key) - .expect("ub: key not found in map") - .as_mut() as *mut (K, V) - } - } -} - -impl> Iterator for MapIter { - type Item = Self; - - fn next(&mut self) -> Option { - if self.is_end() { - return None; - } - let snapshot = self.clone(); - self.inc(); - Some(snapshot) - } -} - -impl> PrefixInc for MapIter { - fn prefix_inc(&mut self) -> Self { - self.inc(); - self.clone() - } -} - -impl> PostfixInc for MapIter { - fn postfix_inc(&mut self) -> Self { - let ret = self.clone(); - self.inc(); - ret - } -} - -impl> PrefixDec for MapIter { - fn prefix_dec(&mut self) -> Self { - self.dec(); - self.clone() - } -} - -impl> PostfixDec for MapIter { - fn postfix_dec(&mut self) -> Self { - let ret = self.clone(); - self.dec(); - ret - } -} +use crate::{CChar, Ptr}; pub struct CStringIterator { pub(crate) ptr: Ptr, diff --git a/rules/algorithm/src.cpp b/rules/algorithm/src.cpp index 40b020c3f..bfed13eaa 100644 --- a/rules/algorithm/src.cpp +++ b/rules/algorithm/src.cpp @@ -9,8 +9,6 @@ #include #include -#include "../common/traits.h" - template void f1(T1 first, T1 last) { return std::sort(first, last); } @@ -27,24 +25,19 @@ template void f6(T1 first, T1 last, T2 comp) { return std::stable_sort(first, last, comp); } -template T1 *f8(T1 *first, T1 *last) { +template T1 f8(T1 first, T1 last) { return std::max_element(first, last); } template void f9(T1 &a0, T1 &a1) { return std::swap(a0, a1); } -template , - typename T2 = AllocatorOf>, - typename = SameAs::iterator>> -typename std::vector::iterator f10(It a0, It a1) { - return std::unique(a0, a1); +template T1 f10(T1 first, T1 last) { + return std::unique(first, last); } -template , - typename T3 = AllocatorOf>, - typename = SameAs::iterator>> -void f12(It a0, It a1, const T2 &a2) { - return std::fill(a0, a1, a2); +template +void f12(T1 first, T1 last, const T2 &value) { + return std::fill(first, last, value); } std::ostream_iterator f13(std::string::iterator a0, diff --git a/rules/algorithm/tgt_refcount.rs b/rules/algorithm/tgt_refcount.rs index 52a96393e..d177de743 100644 --- a/rules/algorithm/tgt_refcount.rs +++ b/rules/algorithm/tgt_refcount.rs @@ -6,55 +6,86 @@ use std::cell::RefCell; use std::io::Write; use std::rc::Rc; -fn f1(a0: Ptr, a1: Ptr) { - a0.sort(a1.get_offset()) +fn f1, T2: Ord + Clone + ByteRepr>(a0: T1, a1: T1) { + let __n = a1.iter_distance(&a0); + let mut __order: Vec = (0..__n).collect(); + __order.sort_by(|&__x, &__y| { + a0.iter_at(__x) + .with(|__a| a0.iter_at(__y).with(|__b| __a.cmp(__b))) + }); + let __values: Vec<_> = __order.iter().map(|&__i| a0.iter_at(__i).read()).collect(); + for (__i, __v) in (0..__n).zip(__values) { + a0.iter_at(__i).write(__v); + } } -fn f2 + ByteRepr>( - a0: Ptr, - a1: Ptr, - a2: Ptr, -) -> Ptr { - let count = a1.get_offset() - a0.get_offset(); - let mut outptr = a2; - for value in PtrValueIter::new(&a0, count) { - outptr.write(value.into()); - outptr += 1; +fn f2< + T1: CppInputIterator, + T2: CppIterator, + T3: Clone + ByteRepr, + T4: From + ByteRepr, +>( + a0: T1, + a1: T1, + a2: T2, +) -> T2 { + let mut __first = a0; + let mut __out = a2; + while __first != a1 { + __out.iter_deref().write(__first.iter_deref().read().into()); + __first.iter_inc(); + __out.iter_inc(); } - outptr + __out } -fn f3(a0: Ptr, a1: Ptr, a2: T1) -> Ptr { - let count = (a1.get_offset() - a0.get_offset()) as usize; - a0.offset( - a0.clone() - .into_iter() - .take(count) - .position(|value_0| value_0.read() == a2) - .unwrap_or(count) as isize, - ) +fn f3, T2, T3: PartialEq + ByteRepr>(a0: T1, a1: T1, a2: T2) -> T1 { + let mut __it = a0; + while __it != a1 && __it.iter_deref().with(|__v| *__v != a2) { + __it.iter_inc(); + } + __it } -fn f6(a0: Ptr, a1: Ptr, a2: T2) +fn f6, T2, T3: Clone + ByteRepr>(a0: T1, a1: T1, a2: T2) where - T2: Callable2, Ptr, bool>, + T2: Callable2, Ptr, bool>, { - a0.sort_with_cmp(a1.get_offset(), |x, y| a2.call(x, y)) + let __n = a1.iter_distance(&a0); + let mut __order: Vec = (0..__n).collect(); + __order.sort_by(|&__x, &__y| { + let __a = a0.iter_at(__x); + let __b = a0.iter_at(__y); + if a2.call(__a.clone(), __b.clone()) { + std::cmp::Ordering::Less + } else if a2.call(__b, __a) { + std::cmp::Ordering::Greater + } else { + std::cmp::Ordering::Equal + } + }); + let __values: Vec<_> = __order.iter().map(|&__i| a0.iter_at(__i).read()).collect(); + for (__i, __v) in (0..__n).zip(__values) { + a0.iter_at(__i).write(__v); + } } -fn f8(a0: Ptr, a1: Ptr) -> Ptr { - let count = a1.get_offset() - a0.get_offset(); - let max_index = PtrValueIter::new(&a0, count) - .enumerate() - .max_by(|(idx_a, val_a), (idx_b, val_b)| { - val_a - .partial_cmp(val_b) - .unwrap_or(std::cmp::Ordering::Equal) - .then_with(|| idx_b.cmp(idx_a)) - }) - .map(|(idx, _)| idx) - .unwrap_or(0); - a0 + max_index +fn f8, T2: PartialOrd + ByteRepr>(a0: T1, a1: T1) -> T1 { + let mut __best = a0.clone(); + if a0 != a1 { + let mut __it = a0; + __it.iter_inc(); + while __it != a1 { + if __best + .iter_deref() + .with(|__b| __it.iter_deref().with(|__v| __b < __v)) + { + __best = __it.clone(); + } + __it.iter_inc(); + } + } + __best } fn f9(a0: Ptr, a1: Ptr) { @@ -63,35 +94,31 @@ fn f9(a0: Ptr, a1: Ptr) { a1.write(tmp); } -fn f10(a0: Ptr, a1: Ptr) -> Ptr { - let count = a1.get_offset() - a0.get_offset(); - if count <= 1 { +fn f10, T2: PartialEq + Clone + ByteRepr>(a0: T1, a1: T1) -> T1 { + if a0 == a1 { a1 } else { - let mut iter = PtrValueIter::new(&a0, count); - let mut write_ptr = a0; - let mut last_unique = iter.next().unwrap(); - - // the first unique value is already in place - write_ptr += 1; - - for current_val in iter { - if current_val != last_unique { - write_ptr.write(current_val.clone()); - last_unique = current_val; - write_ptr += 1; + let mut __write = a0.clone(); + let mut __it = a0; + __it.iter_inc(); + while __it != a1 { + let __v = __it.iter_deref().read(); + if __write.iter_deref().with(|__w| *__w != __v) { + __write.iter_inc(); + __write.iter_deref().write(__v); } + __it.iter_inc(); } - write_ptr + __write.iter_inc(); + __write } } -fn f12(a0: Ptr, a1: Ptr, a2: T1) { - let mut __a0 = a0; - while __a0 != a1 { - let v = a2.clone(); - __a0.write(v); - __a0 += 1; +fn f12, T2: Clone + ByteRepr>(a0: T1, a1: T1, a2: T2) { + let mut __it = a0; + while __it != a1 { + __it.iter_deref().write(Clone::clone(&a2)); + __it.iter_inc(); } } diff --git a/rules/algorithm/tgt_unsafe.rs b/rules/algorithm/tgt_unsafe.rs index 6257589a5..9078e4165 100644 --- a/rules/algorithm/tgt_unsafe.rs +++ b/rules/algorithm/tgt_unsafe.rs @@ -4,90 +4,112 @@ use libcc2rs::*; use std::io::{Seek, Write}; -unsafe fn f1(a0: *mut T1, a1: *mut T1) { - let len = a1.offset_from(a0) as usize; - ::std::slice::from_raw_parts_mut(a0, len).sort() +unsafe fn f1, T2: Ord>(a0: T1, a1: T1) { + let __n = a1.iter_distance(&a0); + let mut __order: Vec = (0..__n).collect(); + __order.sort_by(|&__x, &__y| (*a0.iter_at(__x)).cmp(&*a0.iter_at(__y))); + let __values: Vec<_> = __order + .iter() + .map(|&__i| std::ptr::read(a0.iter_at(__i))) + .collect(); + for (__i, __v) in (0..__n).zip(__values) { + std::ptr::write(a0.iter_at(__i), __v); + } } -unsafe fn f2>(a0: *const T1, a1: *const T1, a2: *mut T2) -> *mut T2 { - let mut outptr = a2.clone(); - let mut curr = a0.clone(); - while curr < a1 { - *outptr = (*curr).clone().into(); - curr = curr.offset(1); - outptr = outptr.offset(1); +unsafe fn f2, T2: UnsafeCppIterator, T3: Clone, T4: From>( + a0: T1, + a1: T1, + a2: T2, +) -> T2 { + let mut __first = a0; + let mut __out = a2; + while __first != a1 { + *__out.iter_deref() = (*__first.iter_deref()).clone().into(); + __first.iter_inc(); + __out.iter_inc(); } - outptr + __out } -unsafe fn f3(a0: *mut T1, a1: *mut T1, a2: T1) -> *mut T1 { - let mut it = a0; - while it != a1 && *it != a2 { - it = it.add(1); +unsafe fn f3, T2, T3: PartialEq>(a0: T1, a1: T1, a2: T2) -> T1 { + let mut __it = a0; + while __it != a1 && *__it.iter_deref() != a2 { + __it.iter_inc(); } - it + __it } -unsafe fn f6(a0: *mut T1, a1: *mut T1, a2: T2) +unsafe fn f6, T2, T3>(a0: T1, a1: T1, a2: T2) where - T2: Callable2<*const T1, *const T1, bool>, + T2: Callable2<*const T3, *const T3, bool>, { - let len = a1.offset_from(a0) as usize; - ::std::slice::from_raw_parts_mut(a0, len).sort_by(|x, y| { - if a2.call(x as *const _, y as *const _) { + let __n = a1.iter_distance(&a0); + let mut __order: Vec = (0..__n).collect(); + __order.sort_by(|&__x, &__y| { + let __a = a0.iter_at(__x) as *const _; + let __b = a0.iter_at(__y) as *const _; + if a2.call(__a, __b) { std::cmp::Ordering::Less - } else if a2.call(y as *const _, x as *const _) { + } else if a2.call(__b, __a) { std::cmp::Ordering::Greater } else { std::cmp::Ordering::Equal } - }) + }); + let __values: Vec<_> = __order + .iter() + .map(|&__i| std::ptr::read(a0.iter_at(__i))) + .collect(); + for (__i, __v) in (0..__n).zip(__values) { + std::ptr::write(a0.iter_at(__i), __v); + } } -unsafe fn f8(a0: *mut T1, a1: *mut T1) -> *mut T1 { - let count = a1.offset_from(a0) as usize; - std::slice::from_raw_parts(a0, count) - .iter() - .enumerate() - .max_by(|(idx_a, x), (idx_b, y)| { - x.partial_cmp(y) - .unwrap_or(std::cmp::Ordering::Equal) - .then_with(|| idx_b.cmp(idx_a)) - }) - .map(|(i, _)| a0.add(i)) - .unwrap_or(a0) +unsafe fn f8, T2: PartialOrd>(a0: T1, a1: T1) -> T1 { + let mut __best = a0.clone(); + if a0 != a1 { + let mut __it = a0; + __it.iter_inc(); + while __it != a1 { + if *__best.iter_deref() < *__it.iter_deref() { + __best = __it.clone(); + } + __it.iter_inc(); + } + } + __best } unsafe fn f9(a0: &mut T1, a1: &mut T1) { std::mem::swap(&mut *a0, &mut *a1) } -unsafe fn f10(a0: *mut T1, a1: *mut T1) -> *mut T1 { +unsafe fn f10, T2: PartialEq + Clone>(a0: T1, a1: T1) -> T1 { if a0 == a1 { - a0 + a1 } else { - let mut write = a0; - let mut prev = a0; - let mut it = a0; - it = it.add(1); - - while it != a1 { - if *prev != *it { - write = write.add(1); - *write = (*it).clone(); - prev = write; + let mut __write = a0.clone(); + let mut __it = a0; + __it.iter_inc(); + while __it != a1 { + if *__write.iter_deref() != *__it.iter_deref() { + __write.iter_inc(); + *__write.iter_deref() = (*__it.iter_deref()).clone(); } - it = it.add(1); + __it.iter_inc(); } - - write = write.add(1); - write + __write.iter_inc(); + __write } } -unsafe fn f12(a0: *mut T1, a1: *mut T1, a2: T1) { - let count = a1.offset_from(a0) as usize; - std::slice::from_raw_parts_mut(a0, count).fill(a2) +unsafe fn f12, T2: Clone>(a0: T1, a1: T1, a2: T2) { + let mut __it = a0; + while __it != a1 { + *__it.iter_deref() = Clone::clone(&a2); + __it.iter_inc(); + } } unsafe fn f13( diff --git a/rules/common/traits.h b/rules/common/traits.h deleted file mode 100644 index 6e50a69e8..000000000 --- a/rules/common/traits.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2022-present INESC-ID. -// Distributed under the MIT license that can be found in the LICENSE file. - -template struct EnableIf {}; - -template struct EnableIf { - using type = T; -}; - -template struct IsSame { - static constexpr bool value = false; -}; - -template struct IsSame { - static constexpr bool value = true; -}; - -template struct RemoveConst { - using type = T; -}; - -template struct RemoveConst { - using type = T; -}; - -template struct FindAlloc { - using type = D; -}; - -template class C, - typename A, typename... Args> -struct FindAlloc, Args...> { - using type = A; -}; - -template -struct FindAlloc : FindAlloc {}; - -template struct AllocOf { - using type = D; -}; - -template