From 8ad78aef559c80d0966ce082dacb250218f77f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gouveia?= Date: Fri, 14 Aug 2026 09:59:11 +0000 Subject: [PATCH] Add rule hint header --- cpp2rust/CMakeLists.txt | 2 + cpp2rust/converter/mapper.cpp | 86 ++- cpp2rust/converter/mapper.h | 9 +- cpp2rust/cpp_rule_preprocessor.cpp | 771 +++----------------- libcc2rs/src/iterators.rs | 11 +- rule-preprocessor/src/syntactic.rs | 8 +- rules/algorithm/src.cpp | 95 +-- rules/array/src.cpp | 3 +- rules/cstddef/src.cpp | 24 + rules/cstddef/tgt_unsafe.rs | 38 + rules/iterator/src.cpp | 71 ++ rules/iterator/tgt_unsafe.rs | 52 ++ rules/lib/rule_hints.h | 462 ++++++++++++ rules/lib/rule_tags.h | 5 + rules/map/src.cpp | 17 +- rules/pair/src.cpp | 11 +- rules/src/modules.rs | 4 + rules/unique_ptr/src.cpp | 5 +- rules/vector/src.cpp | 116 +-- tests/unit/byte.cpp | 44 ++ tests/unit/out/refcount/byte.rs | 56 ++ tests/unit/out/refcount/reverse_iterator.rs | 84 +++ tests/unit/out/unsafe/byte.rs | 58 ++ tests/unit/out/unsafe/reverse_iterator.rs | 50 ++ tests/unit/reverse_iterator.cpp | 38 + 25 files changed, 1260 insertions(+), 860 deletions(-) create mode 100644 rules/cstddef/src.cpp create mode 100644 rules/cstddef/tgt_unsafe.rs create mode 100644 rules/iterator/src.cpp create mode 100644 rules/iterator/tgt_unsafe.rs create mode 100644 rules/lib/rule_hints.h create mode 100644 rules/lib/rule_tags.h create mode 100644 tests/unit/byte.cpp create mode 100644 tests/unit/out/refcount/byte.rs create mode 100644 tests/unit/out/refcount/reverse_iterator.rs create mode 100644 tests/unit/out/unsafe/byte.rs create mode 100644 tests/unit/out/unsafe/reverse_iterator.rs create mode 100644 tests/unit/reverse_iterator.cpp diff --git a/cpp2rust/CMakeLists.txt b/cpp2rust/CMakeLists.txt index 864cc7c07..7ad21c6a3 100644 --- a/cpp2rust/CMakeLists.txt +++ b/cpp2rust/CMakeLists.txt @@ -43,3 +43,5 @@ target_link_libraries(cpp2rust PRIVATE cpp2rust_core) add_clang_executable(cpp-rule-preprocessor PARTIAL_SOURCES_INTENDED cpp_rule_preprocessor.cpp) target_link_libraries(cpp-rule-preprocessor PRIVATE cpp2rust_core) +target_compile_definitions(cpp-rule-preprocessor PRIVATE + "-DRULES_LIB_INCLUDE_DIR=\"${PROJECT_SOURCE_DIR}/rules/lib\"") diff --git a/cpp2rust/converter/mapper.cpp b/cpp2rust/converter/mapper.cpp index 83ebc988e..fc9e77151 100644 --- a/cpp2rust/converter/mapper.cpp +++ b/cpp2rust/converter/mapper.cpp @@ -4,6 +4,7 @@ #include "converter/mapper.h" #include +#include #include #include #include @@ -558,7 +559,8 @@ void addBuiltinTypes(Model model) { add_size_rules(ctx_->getSignedSizeType(), {"ssize_t"}, "isize"); } -clang::QualType normalizeQualType(clang::QualType qual_type) { +clang::QualType normalizeQualType(clang::QualType qual_type, + const clang::DeclContext *dctx) { assert(ctx_); bool isLRef = qual_type->isLValueReferenceType(); @@ -584,6 +586,22 @@ clang::QualType normalizeQualType(clang::QualType qual_type) { qual_type = qual_type.getCanonicalType(); } + bool sugared = false; + if (dctx && llvm::isa(qual_type)) { + const auto match = llvm::find_if(dctx->decls(), [&](const auto *d) { + const auto *td = llvm::dyn_cast(d); + return td && (td->getUnderlyingType().getCanonicalType() == + qual_type.getCanonicalType()); + }); + + if (match != dctx->decls().end()) { + qual_type = + ctx_->getTypedefType(clang::ElaboratedTypeKeyword::None, std::nullopt, + llvm::cast(*match)); + sugared = true; + } + } + qual_type = qual_type.withFastQualifiers(qualifiers.getFastQualifiers()); if (qualifiers.hasNonFastQualifiers()) { qual_type = ctx_->getQualifiedType(qual_type, qualifiers); @@ -597,6 +615,9 @@ clang::QualType normalizeQualType(clang::QualType qual_type) { qual_type = ctx_->getRValueReferenceType(qual_type); } + if (sugared) { + return qual_type; + } return qual_type.getCanonicalType().getUnqualifiedType().getDesugaredType( *ctx_); } @@ -834,7 +855,8 @@ std::string ToRustName(std::string name) { return ReplaceAll(name, "::", "_"); } -std::string ToString(clang::QualType qual_type, ScalarSugar sugar) { +std::string ToString(clang::QualType qual_type, ScalarSugar sugar, + const clang::DeclContext *dctx) { assert(ctx_); if (sugar == ScalarSugar::kPreserve) { @@ -864,7 +886,7 @@ std::string ToString(clang::QualType qual_type, ScalarSugar sugar) { if (auto cxx_record_decl = qual_type->getAsCXXRecordDecl()) { if (cxx_record_decl->isLambda()) { - return ToString(cxx_record_decl->getLambdaCallOperator()); + return ToString(cxx_record_decl->getLambdaCallOperator(), dctx); } } @@ -880,11 +902,12 @@ std::string ToString(clang::QualType qual_type, ScalarSugar sugar) { std::string type; llvm::raw_string_ostream os(type); - normalizeQualType(qual_type).print(os, getPrintPolicy()); + normalizeQualType(qual_type, dctx).print(os, getPrintPolicy()); return normalizeTranslationRule(std::move(type)); } -std::string ToString(const clang::NamedDecl *decl) { +std::string ToString(const clang::NamedDecl *decl, + const clang::DeclContext *dctx) { if (auto *record = clang::dyn_cast(decl); record && !record->getIdentifier()) { if (auto renamed = DisambiguateAnonymousTag(record); !renamed.empty()) { @@ -921,9 +944,32 @@ std::string ToString(const clang::NamedDecl *decl) { return normalizeTranslationRule(std::move(out)); } - os << ToString(func_decl->getReturnType()) << ' '; - if (const auto *method_decl = - llvm::dyn_cast(func_decl)) { + os << ToString(func_decl->getReturnType(), ScalarSugar::kDesugar, dctx) + << ' '; + if (const auto op = func_decl->getOverloadedOperator(); + op >= clang::OverloadedOperatorKind::OO_LessLess && + op <= clang::OverloadedOperatorKind::OO_GreaterGreaterEqual) { + // ensure matchTemplate does not consider these operator names when matching + func_decl->getQualifier().print(os, getPrintPolicy()); + os << "operator "; + switch (op) { + case clang::OverloadedOperatorKind::OO_LessLess: + os << "shl"; + break; + case clang::OverloadedOperatorKind::OO_GreaterGreater: + os << "shr"; + break; + case clang::OverloadedOperatorKind::OO_LessLessEqual: + os << "shleq"; + break; + case clang::OverloadedOperatorKind::OO_GreaterGreaterEqual: + os << "shreq"; + break; + default: + std::unreachable(); + } + } else if (const auto *method_decl = + llvm::dyn_cast(func_decl)) { if (method_decl->getParent()->isLambda() && method_decl->getOverloadedOperator() == clang::OO_Call) { func_decl->printName(os, getPrintPolicy()); @@ -939,7 +985,8 @@ std::string ToString(const clang::NamedDecl *decl) { if (i) { os << ", "; } - os << ToString(func_decl->getParamDecl(i)->getType()); + os << ToString(func_decl->getParamDecl(i)->getType(), ScalarSugar::kDesugar, + dctx); } if (func_decl->isVariadic()) { if (func_decl->getNumParams()) { @@ -972,7 +1019,7 @@ std::string ToString(const clang::NamedDecl *decl) { return normalizeTranslationRule(std::move(out)); } -std::string ToString(const clang::Expr *expr) { +std::string ToString(const clang::Expr *expr, const clang::DeclContext *dctx) { if (!expr) { assert(0 && "!expr"); } @@ -991,13 +1038,13 @@ std::string ToString(const clang::Expr *expr) { if (const auto *CE = llvm::dyn_cast(expr)) { if (const auto *decl = CE->getDirectCallee()) { - return ToString(decl); + return ToString(decl, dctx); } } if (const auto *ctor = llvm::dyn_cast(expr)) { if (const auto *ctor_decl = ctor->getConstructor()) { - return ToString(ctor_decl); + return ToString(ctor_decl, dctx); } assert(0 && "expr is a CXXConstructExpr but could not get constructor"); } @@ -1007,14 +1054,15 @@ std::string ToString(const clang::Expr *expr) { llvm::dyn_cast(ME->getMemberDecl())) { if (const auto *method_decl = llvm::dyn_cast(member_decl)) { - return ToString(method_decl); + return ToString(method_decl, dctx); } if (ME->isArrow()) { auto *base = ME->getBase()->IgnoreParenImpCasts(); if (auto *op = llvm::dyn_cast(base)) { if (op->getOperator() == clang::OO_Arrow) { - return ToString(op->getArg(0)->getType()) + "->" + - ToString(member_decl); + return ToString(op->getArg(0)->getType(), ScalarSugar::kDesugar, + dctx) + + "->" + ToString(member_decl, dctx); } } } else if (auto for_range = GetParentForRange(*ctx_, ME)) { @@ -1026,7 +1074,7 @@ std::string ToString(const clang::Expr *expr) { } } } - return ToString(member_decl); + return ToString(member_decl, dctx); } assert(0 && "expr is a MemberExpr but could not get named decl"); } @@ -1036,15 +1084,15 @@ std::string ToString(const clang::Expr *expr) { llvm::dyn_cast(decl_ref->getDecl())) { if (const auto *tmpl_decl = llvm::dyn_cast(named_decl)) { - return ToString(tmpl_decl->getTemplatedDecl()); + return ToString(tmpl_decl->getTemplatedDecl(), dctx); } - return ToString(named_decl); + return ToString(named_decl, dctx); } return ""; } if (const auto *uop = llvm::dyn_cast(expr)) { - auto sub = ToString(uop->getSubExpr()); + auto sub = ToString(uop->getSubExpr(), dctx); std::string_view opcode = clang::UnaryOperator::getOpcodeStr(uop->getOpcode()); return uop->isPostfix() ? std::format("{}{}", sub, opcode) diff --git a/cpp2rust/converter/mapper.h b/cpp2rust/converter/mapper.h index 92f6f7f63..215b42b2c 100644 --- a/cpp2rust/converter/mapper.h +++ b/cpp2rust/converter/mapper.h @@ -48,9 +48,12 @@ enum class ScalarSugar { clang::QualType GetTypeForDecl(const clang::NamedDecl *decl); std::string ToString(clang::QualType qual_type, - ScalarSugar sugar = ScalarSugar::kDesugar); -std::string ToString(const clang::Expr *expr); -std::string ToString(const clang::NamedDecl *decl); + ScalarSugar sugar = ScalarSugar::kDesugar, + const clang::DeclContext *dctx = nullptr); +std::string ToString(const clang::Expr *expr, + const clang::DeclContext *dctx = nullptr); +std::string ToString(const clang::NamedDecl *decl, + const clang::DeclContext *dctx = nullptr); std::string ToRustName(std::string name); void LoadTranslationRules(Model model, clang::ASTContext &ctx, diff --git a/cpp2rust/cpp_rule_preprocessor.cpp b/cpp2rust/cpp_rule_preprocessor.cpp index 408c80d6f..8ac38be28 100644 --- a/cpp2rust/cpp_rule_preprocessor.cpp +++ b/cpp2rust/cpp_rule_preprocessor.cpp @@ -37,52 +37,6 @@ namespace fs = std::filesystem; namespace cpp2rust { -enum LookupKind { RegularName, CXXMethodName, CXXConstructorName, ADL }; - -struct LookupInfo { - clang::DeclarationName name; - LookupKind kind; - llvm::ArrayRef explicitArgs; - - LookupInfo(const clang::Expr *expr) { - if (const auto *ul = llvm::dyn_cast(expr)) { - clang::DeclarationName dname = ul->getName(); - name = dname; - if (ul->requiresADL()) { - kind = LookupKind::ADL; - } else { - kind = LookupKind::RegularName; - } - explicitArgs = ul->template_arguments(); - } else if (const auto *dm = - llvm::dyn_cast(expr)) { - name = dm->getMember(); - kind = LookupKind::CXXMethodName; - explicitArgs = dm->template_arguments(); - } else if (const auto *um = - llvm::dyn_cast(expr)) { - name = um->getMemberName(); - kind = LookupKind::CXXMethodName; - explicitArgs = um->template_arguments(); - } else if (const auto *dref = - llvm::dyn_cast(expr)) { - clang::DeclarationName dname = dref->getDeclName(); - if (dname.getNameKind() == - clang::DeclarationName::NameKind::CXXConstructorName) { - name = dname; - kind = LookupKind::CXXConstructorName; - } else { - assert(0 && "Unsupported dref name kind"); - } - } else if (llvm::isa(expr)) { - kind = LookupKind::CXXConstructorName; - } else { - expr->dump(); - assert(0 && "Unsupported lookup expression"); - } - } -}; - class Callback : public clang::ast_matchers::MatchFinder::MatchCallback { public: explicit Callback(llvm::json::Object &out) : out_(out) {} @@ -96,7 +50,10 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback { void run(const clang::ast_matchers::MatchFinder::MatchResult &R) override { assert(sema_); Mapper::PushASTContext scoped(*R.Context); - if (auto func = R.Nodes.getNodeAs("validate_func")) { + clang::NamespaceDecl *ns = createNamespaceDecl(); + const clang::Sema::ContextRAII savedContext(*sema_, ns); + + if (auto func = R.Nodes.getNodeAs("func")) { const char *err = nullptr; if (auto body = clang::dyn_cast_or_null(func->getBody())) { @@ -114,101 +71,35 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback { << err << '\n'; std::exit(EXIT_FAILURE); } + + auto *rule = func; + if (auto *tdecl = func->getDescribedFunctionTemplate()) { + rule = instantiateFunctionRule(tdecl); + assert(rule && "Instantiation failed"); + } + + auto *body = llvm::cast(rule->getBody()); + auto *ret = llvm::cast(*body->body_begin()); + auto src = Mapper::ToString( + ret->getRetValue()->IgnoreUnlessSpelledInSource(), sema_->CurContext); + assert(src != "Unhandled case in ToString"); + out_.try_emplace(rule->getQualifiedNameAsString(), std::move(src)); return; } + if (auto var = R.Nodes.getNodeAs("tvar")) { clang::QualType type = var->getUnderlyingType(); if (auto *alias = llvm::dyn_cast(var)) { if (auto *tdecl = alias->getDescribedAliasTemplate()) { - type = lookupType(tdecl); + type = instantiateTypeRule(tdecl); } } - auto src = Mapper::ToString(type, Mapper::ScalarSugar::kPreserve); + auto src = Mapper::ToString(type, Mapper::ScalarSugar::kPreserve, + sema_->CurContext); + assert(src != "Unhandled case in ToString"); out_.try_emplace(var->getQualifiedNameAsString(), std::move(src)); return; } - - if (auto func = R.Nodes.getNodeAs("func")) { - auto add = [&](std::string &&src) { - out_.try_emplace(func->getQualifiedNameAsString(), std::move(src)); - }; - - if (const auto *fcall = R.Nodes.getNodeAs("fcall")) { - if (fcall->getDirectCallee()) { - add(Mapper::ToString(fcall)); - return; - } - - LookupInfo lookup(fcall->getCallee()); - clang::NamedDecl *decl = - lookupCalledDecl(func->getDescribedFunctionTemplate(), lookup); - add(Mapper::ToString(decl)); - return; - } - if (const auto *ctor = - R.Nodes.getNodeAs("ctor")) { - if (ctor->getConstructor()) { - add(Mapper::ToString(ctor)); - return; - } - } - if (const auto *muse = R.Nodes.getNodeAs("muse")) { - if (llvm::isa(muse->getMemberDecl())) { - add(Mapper::ToString(muse)); - return; - } - } - if (const auto *um = - R.Nodes.getNodeAs("umuse")) { - add(Mapper::ToString(um)); - return; - } - if (R.Nodes.getNodeAs("declref")) { - if (const auto *enum_val = - R.Nodes.getNodeAs("enum_val")) { - add(Mapper::ToString(enum_val)); - return; - } else if (const auto *decl = - R.Nodes.getNodeAs("decl")) { - add(Mapper::ToString(decl)); - return; - } - } - if (const auto *uop = - R.Nodes.getNodeAs("udeclref")) { - add(Mapper::ToString(uop)); - return; - } - if (const auto *dsme = - R.Nodes.getNodeAs("dsme")) { - if (dsme->isArrow()) { - clang::MemberExpr *expr = lookupArrowAccess( - func->getDescribedFunctionTemplate(), dsme->getMemberNameInfo(), - dsme->getQualifierLoc()); - add(Mapper::ToString(expr)); - return; - } - clang::NamedDecl *decl = lookupMemberAccess( - func->getDescribedFunctionTemplate(), dsme->getMember()); - add(Mapper::ToString(decl)); - return; - } - if (const auto *uctor = - R.Nodes.getNodeAs("uctor")) { - LookupInfo lookup(uctor); - clang::NamedDecl *decl = - lookupCalledDecl(func->getDescribedFunctionTemplate(), lookup); - add(Mapper::ToString(decl)); - return; - } - if (const auto *lit = - R.Nodes.getNodeAs("macro_int")) { - if (lit->getBeginLoc().isMacroID()) { - add(Mapper::ToString(lit)); - } - return; - } - } } private: @@ -216,81 +107,6 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback { clang::Sema *sema_ = nullptr; clang::SourceLocation loc_; - void forceCompleteDefinition(clang::QualType type) { - type = type.getCanonicalType(); - if (type->isPointerType()) { - type = type->getPointeeType(); - } - - if (!type->isIncompleteType()) { - return; - } - - sema_->RequireCompleteType(loc_, type, - clang::Sema::CompleteTypeKind::Normal, - clang::diag::err_incomplete_type); - - if (auto *spec = - llvm::dyn_cast_or_null( - type->getAsCXXRecordDecl())) { - for (const auto *decl : spec->decls()) { - if (const auto *tdef = llvm::dyn_cast(decl)) { - clang::QualType tdef_t = tdef->getUnderlyingType(); - forceCompleteDefinition(tdef_t); - } - } - - for (const auto &arg : spec->getTemplateArgs().asArray()) { - if (arg.getKind() == clang::TemplateArgument::Type) { - forceCompleteDefinition(arg.getAsType()); - } - } - } - } - - clang::FunctionDecl *deduceTemplateArguments( - clang::FunctionTemplateDecl *decl, llvm::ArrayRef callArgs, - clang::QualType obj_t, clang::Expr::Classification exprClass, - clang::TemplateArgumentListInfo *explicitArgs = nullptr) { - clang::FunctionDecl *spec = nullptr; - clang::sema::TemplateDeductionInfo info((loc_)); - auto check = [](llvm::ArrayRef, bool) -> bool { - return false; - }; - - auto result = sema_->DeduceTemplateArguments( - decl, explicitArgs, callArgs, spec, info, false, false, false, obj_t, - exprClass, false, check); - - if (result == clang::TemplateDeductionResult::Success) { - return spec; - } - - if (result == clang::TemplateDeductionResult::SubstitutionFailure || - result == clang::TemplateDeductionResult::ConstraintsNotSatisfied) { - if (const auto *deduced = info.takeCanonical()) { - clang::TemplateArgumentListInfo targsInfo; - for (const auto &arg : deduced->asArray()) { - targsInfo.addArgument( - sema_->getTrivialTemplateArgumentLoc(arg, {}, loc_)); - } - - clang::DefaultArguments defaultArgs; - clang::Sema::CheckTemplateArgumentInfo ctai; - clang::Sema::InstantiatingTemplate Inst(*sema_, loc_, decl); - auto invalid = sema_->CheckTemplateArgumentList( - decl, decl->getTemplateParameters(), loc_, targsInfo, defaultArgs, - true, ctai); - - if (!invalid) { - return sema_->InstantiateFunctionDeclaration(decl, deduced, loc_); - } - } - } - - return nullptr; - } - clang::NamespaceDecl *createNamespaceDecl() { auto &ctx = sema_->getASTContext(); auto *tu = ctx.getTranslationUnitDecl(); @@ -300,9 +116,7 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback { return ns; } - clang::RecordDecl * - createRecordDecl(llvm::StringRef name, - clang::QualType base = clang::QualType()) { + clang::RecordDecl *createRecordDecl(llvm::StringRef name) { bool owned = true; bool dependent = false; clang::CXXScopeSpec scope; @@ -317,14 +131,6 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback { auto *rdecl = decl.getAs(); rdecl->startDefinition(); - if (!base.isNull()) { - clang::CXXBaseSpecifier baseSpec( - clang::SourceRange(loc_, loc_), false, true, clang::AS_public, - sema_->Context.getTrivialTypeSourceInfo(base, loc_), - /*EllipsisLoc=*/clang::SourceLocation()); - const clang::CXXBaseSpecifier *bases[] = {&baseSpec}; - llvm::cast(rdecl)->setBases(bases, 1); - } rdecl->completeDefinition(); return rdecl; } @@ -345,10 +151,11 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback { } clang::QualType - getTemplateIdType(clang::ClassTemplateDecl *decl, + getTemplateIdType(clang::TemplateDecl *decl, llvm::ArrayRef args) { clang::TemplateArgumentListInfo info(loc_, loc_); - for (const clang::TemplateArgument &arg : args) { + for (const auto &arg : args) { + assert(!arg.getIsDefaulted()); info.addArgument( sema_->getTrivialTemplateArgumentLoc(arg, getNTTPType(arg), loc_)); } @@ -358,115 +165,24 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback { /*ForNestedNameSpecifier=*/false); } - using MirrorMap = llvm::SmallDenseMap; - - clang::TypeSourceInfo *findMatch(MirrorMap &substs, clang::QualType type) { - const auto *tst = type->getAs(); - if (!tst) { - return nullptr; - } - - const auto *tdecl = llvm::dyn_cast_or_null( - tst->getTemplateName().getAsTemplateDecl()); - if (!tdecl) { - return nullptr; - } - - if (auto it = substs.find(tdecl->getCanonicalDecl()); it != substs.end()) { - auto match = getTemplateIdType(it->second, tst->template_arguments()); - assert(!match.isNull()); - return sema_->Context.getTrivialTypeSourceInfo(match, loc_); - } - return nullptr; - } - - clang::ClassTemplateDecl * - createInheritingTemplate(llvm::StringRef name, clang::ClassTemplateDecl *decl, - MirrorMap &substs) { + clang::QualType createAliasType(llvm::StringRef name, clang::QualType hint) { clang::ASTContext &ctx = sema_->Context; - auto *pattern = clang::CXXRecordDecl::Create( - ctx, clang::TagTypeKind::Struct, sema_->CurContext, loc_, loc_, - &ctx.Idents.get(name)); - - auto *mirror = clang::ClassTemplateDecl::Create( - ctx, sema_->CurContext, loc_, - clang::DeclarationName(&ctx.Idents.get(name)), - decl->getTemplateParameters(), pattern); - pattern->setDescribedClassTemplate(mirror); - mirror->setAccess(clang::AS_public); - substs.try_emplace(decl->getCanonicalDecl(), mirror); - - clang::QualType base_t = getTemplateIdType( - decl, decl->getTemplateParameters()->getInjectedTemplateArgs(ctx)); - assert(!base_t.isNull() && "Failed building mirror base"); - - pattern->startDefinition(); - clang::CXXBaseSpecifier base(clang::SourceRange(loc_, loc_), false, true, - clang::AS_public, - ctx.getTrivialTypeSourceInfo(base_t, loc_), - /*EllipsisLoc=*/clang::SourceLocation()); - const clang::CXXBaseSpecifier *bases[] = {&base}; - pattern->setBases(bases, 1); - - for (auto *member : decl->getTemplatedDecl()->decls()) { - if (const auto *td = llvm::dyn_cast(member)) { - if (auto *replacement = findMatch(substs, td->getUnderlyingType())) { - auto *copy = clang::TypedefDecl::Create( - ctx, pattern, loc_, loc_, td->getIdentifier(), replacement); - copy->setAccess(clang::AS_public); - pattern->addDecl(copy); - } - } else if (auto *tdecl = - llvm::dyn_cast(member)) { - clang::Sema::ContextRAII savedContext(*sema_, pattern); - createInheritingTemplate(tdecl->getName(), tdecl, substs); - } - } - - pattern->completeDefinition(); - sema_->CurContext->addDecl(mirror); - return mirror; - } - - clang::QualType createMirrorType(llvm::StringRef name, clang::QualType hint) { - clang::ASTContext &ctx = sema_->Context; - forceCompleteDefinition(hint); - - const auto *hdecl = hint->getAsCXXRecordDecl(); - assert(hdecl && "Failed resolving hint record declaration"); - assert(hdecl->isCompleteDefinition() && "Incomplete hint"); - - const auto *hspec = - llvm::dyn_cast(hdecl); - if (!hspec) { - // if it is not a template specialization inheriting from it suffices - clang::RecordDecl *rdecl = createRecordDecl(name, hint); - return ctx.getTagType(clang::ElaboratedTypeKeyword::None, - rdecl->getQualifier(), rdecl, false); - } - - MirrorMap substs; - auto *mirror = - createInheritingTemplate(name, hspec->getSpecializedTemplate(), substs); - clang::QualType spec = - getTemplateIdType(mirror, hspec->getTemplateArgs().asArray()); - assert(!spec.isNull() && spec->getAsCXXRecordDecl()); // required to print Tn instead of Tn - clang::NamespaceDecl *ns = createNamespaceDecl(); - auto *alias = - clang::TypeAliasDecl::Create(ctx, ns, loc_, loc_, &ctx.Idents.get(name), - ctx.getTrivialTypeSourceInfo(spec, loc_)); - ns->addDecl(alias); + auto *alias = clang::TypeAliasDecl::Create( + ctx, sema_->CurContext, loc_, loc_, &ctx.Idents.get(name), + ctx.getTrivialTypeSourceInfo(hint, loc_)); + sema_->CurContext->addDecl(alias); clang::QualType alias_t = ctx.getTypedefType( clang::ElaboratedTypeKeyword::None, std::nullopt, alias); - spec->getAsCXXRecordDecl()->addAttr( - clang::PreferredNameAttr::CreateImplicit( - ctx, ctx.getTrivialTypeSourceInfo(alias_t, loc_))); - return ctx.getCanonicalType(spec); + if (auto *hdecl = hint->getAsCXXRecordDecl()) { + hdecl->dropAttr(); + hdecl->addAttr(clang::PreferredNameAttr::CreateImplicit( + ctx, ctx.getTrivialTypeSourceInfo(alias_t, loc_))); + } + return hint; } clang::QualType getSubstType(const clang::Sema::InstantiatingTemplate &Inst, @@ -497,38 +213,25 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback { return getSubstType(Inst, type, currentArgs); } - clang::VarDecl *createVarDecl(clang::QualType type, llvm::StringRef name, - clang::StorageClass sclass = clang::SC_None) { + clang::DeclRefExpr *createConstexprDeclRefExpr(clang::QualType type, + clang::Expr *init, + llvm::StringRef name) { clang::ASTContext &ctx = sema_->Context; clang::VarDecl *decl = clang::VarDecl::Create( ctx, sema_->CurContext, loc_, loc_, &ctx.Idents.get(name), - type.getNonReferenceType(), nullptr, sclass); + type.getNonReferenceType(), nullptr, clang::SC_Static); sema_->CurContext->addDecl(decl); decl->markUsed(ctx); - return decl; - } - - clang::DeclRefExpr *createDeclRefExpr(clang::VarDecl *decl) { - const clang::DeclarationNameInfo nameInfo(decl->getDeclName(), loc_); - return sema_->BuildDeclRefExpr(decl, decl->getType(), clang::VK_LValue, - nameInfo, decl->getQualifierLoc()); - } - - clang::DeclRefExpr *createConstexprDeclRefExpr(clang::QualType type, - llvm::StringRef name) { - clang::VarDecl *decl = createVarDecl(type, name, clang::SC_Static); decl->setConstexpr(true); - clang::Expr *init; - clang::ASTContext &ctx = sema_->Context; - if (type->isIntegerType()) { - init = clang::IntegerLiteral::Create( - ctx, llvm::APInt(ctx.getIntWidth(type), 1), type, loc_); - } else { + if (!init) { init = new (ctx) clang::ImplicitValueInitExpr(type); } decl->setInit(init); - return createDeclRefExpr(decl); + + const clang::DeclarationNameInfo nameInfo(decl->getDeclName(), loc_); + return sema_->BuildDeclRefExpr(decl, decl->getType(), clang::VK_LValue, + nameInfo, decl->getQualifierLoc()); } clang::OpaqueValueExpr *createOpaqueValueExpr(clang::QualType type) { @@ -551,7 +254,7 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback { if (ttp->hasDefaultArgument()) { clang::QualType hint = getDefaultArg(decl, ttp, out); assert(!hint.isNull() && "Failed retrieving type hint"); - type = createMirrorType(param->getName(), hint); + type = createAliasType(param->getName(), hint); } else { clang::RecordDecl *rdecl = createRecordDecl(param->getName()); type = sema_->Context.getTagType(clang::ElaboratedTypeKeyword::None, @@ -566,8 +269,16 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback { const clang::Sema::InstantiatingTemplate Inst(*sema_, loc_, decl); type = getSubstType(Inst, type, out); } + clang::Expr *hint = nullptr; + if (nttp->hasDefaultArgument()) { + auto *arg = nttp->getDefaultArgument().getArgument().getAsExpr(); + if (auto *init = llvm::dyn_cast(arg)) { + hint = llvm::cast(init->getDecl())->getInit(); + type = hint->getType(); + } + } clang::DeclRefExpr *var = - createConstexprDeclRefExpr(type, param->getName()); + createConstexprDeclRefExpr(type, hint, param->getName()); out.emplace_back(var, true); } else { assert(0 && "Unsupported template param kind"); @@ -575,324 +286,28 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback { } } - clang::FunctionDecl *instantiateRuleDecl(clang::FunctionTemplateDecl *decl) { + clang::FunctionDecl * + instantiateFunctionRule(clang::FunctionTemplateDecl *decl) { llvm::SmallVector args; createTemplateArguments(decl, args); - return sema_->InstantiateFunctionDeclaration( + auto *inst = sema_->InstantiateFunctionDeclaration( decl, clang::TemplateArgumentList::CreateCopy(sema_->Context, args), loc_); + assert(inst && "Function rule instantiation failed"); + sema_->InstantiateFunctionDefinition(loc_, inst); + return inst; } - clang::FunctionDecl *createCandidate( - clang::NamedDecl *decl, llvm::ArrayRef callArgs, - clang::TemplateArgumentListInfo *explicitArgs = nullptr, - clang::QualType obj_t = clang::QualType(), - clang::Expr::Classification eclass = clang::Expr::Classification()) { - if (auto *tdecl = llvm::dyn_cast(decl)) { - if (auto *fdecl = deduceTemplateArguments(tdecl, callArgs, obj_t, eclass, - explicitArgs)) { - return fdecl; - } - return nullptr; - } - return llvm::dyn_cast(decl); - } - - clang::CXXRecordDecl *resolveCXXRecordDecl(clang::QualType obj_t) { - obj_t = obj_t.getCanonicalType(); - while (obj_t->isPointerOrReferenceType()) { - obj_t = obj_t->getPointeeType(); - } - - forceCompleteDefinition(obj_t); - if (auto *rdecl = obj_t->getAsCXXRecordDecl()) { - return rdecl->getDefinition(); - } - return nullptr; - } - - void regularNameLookup(llvm::ArrayRef callArgs, - clang::TemplateArgumentListInfo *explicitTArgs, - clang::DeclarationName &name, - clang::OverloadCandidateSet &candidates) { - clang::LookupResult decls(*sema_, name, loc_, - clang::Sema::LookupOrdinaryName); - if (clang::NamespaceDecl *std_ns = sema_->getStdNamespace()) { - sema_->LookupQualifiedName(decls, std_ns); - } - if (decls.empty()) { - decls.clear(); - sema_->LookupQualifiedName(decls, - sema_->Context.getTranslationUnitDecl()); - } - for (auto *ndecl : decls) { - if (auto *candidate = createCandidate(ndecl, callArgs, explicitTArgs)) { - sema_->AddOverloadCandidate( - candidate, clang::DeclAccessPair::make(candidate, clang::AS_public), - callArgs, candidates, false); - } - } - - for (const auto *arg : callArgs) { - if (auto *rdecl = resolveCXXRecordDecl(arg->getType())) { - for (auto *frdecl : rdecl->friends()) { - auto *fd = frdecl->getFriendDecl(); - if (!fd) { - continue; - } - - if (auto *ndecl = llvm::dyn_cast(fd); - ndecl && ndecl->getDeclName() == name) { - if (auto *candidate = - createCandidate(ndecl, callArgs, explicitTArgs)) { - sema_->AddOverloadCandidate( - candidate, - clang::DeclAccessPair::make(candidate, clang::AS_public), - callArgs, candidates, false); - } - } - } - } - } - } - - void cxxMethodNameLookup(clang::QualType obj_t, - llvm::ArrayRef callArgs, - clang::TemplateArgumentListInfo *explicitTArgs, - clang::DeclarationName &name, - clang::OverloadCandidateSet &candidates) { - clang::CXXRecordDecl *rdecl = resolveCXXRecordDecl(obj_t); - assert(rdecl && "Failed fetching record decl"); - clang::LookupResult members(*sema_, name, loc_, - clang::Sema::LookupMemberName); - sema_->LookupQualifiedName(members, rdecl); - - auto eclass = clang::Expr::Classification::makeSimpleLValue(); - for (auto *ndecl : members) { - if (auto *candidate = - createCandidate(ndecl, callArgs, explicitTArgs, obj_t, eclass)) { - sema_->AddMethodCandidate( - clang::DeclAccessPair::make(candidate, clang::AS_public), obj_t, - eclass, callArgs, candidates); - } - } - } - - void cxxConstructorNameLookup(clang::QualType obj_t, - llvm::ArrayRef callArgs, - clang::OverloadCandidateSet &candidates) { - clang::CXXRecordDecl *rdecl = resolveCXXRecordDecl(obj_t); - assert(rdecl && "Failed fetching record decl"); - clang::DeclContextLookupResult ctors = sema_->LookupConstructors(rdecl); - - for (auto *ndecl : ctors) { - if (auto *candidate = createCandidate(ndecl, callArgs)) { - sema_->AddOverloadCandidate( - candidate, clang::DeclAccessPair::make(candidate, clang::AS_public), - callArgs, candidates, false); - } - } - } - - void adlLookup(llvm::ArrayRef callArgs, - clang::DeclarationName &name, - clang::OverloadCandidateSet &candidates) { - clang::ADLResult adl; - sema_->ArgumentDependentLookup(name, loc_, callArgs, adl); - - for (auto *ndecl : adl) { - if (auto *candidate = createCandidate(ndecl, callArgs)) { - sema_->AddOverloadCandidate( - candidate, clang::DeclAccessPair::make(candidate, clang::AS_public), - callArgs, candidates, false); - } - } - } - - clang::FunctionDecl *lookupCalledDecl(clang::FunctionTemplateDecl *decl, - LookupInfo &lookup) { - clang::NamespaceDecl *ns = createNamespaceDecl(); - clang::Sema::ContextRAII savedContext(*sema_, ns); - clang::FunctionDecl *rule = instantiateRuleDecl(decl); - assert(rule && "Rule instantiation failed"); - llvm::ArrayRef parms = rule->parameters(); - auto csk = lookup.name.getNameKind() == - clang::DeclarationName::NameKind::CXXOperatorName - ? clang::OverloadCandidateSet::CSK_Operator - : clang::OverloadCandidateSet::CSK_Normal; - - llvm::SmallVector callArgs; - for (const auto *parm : parms) { - clang::QualType parm_t = parm->getType(); - forceCompleteDefinition(parm_t); - callArgs.emplace_back(createOpaqueValueExpr(parm_t)); - } - - llvm::ArrayRef ruleTArgs = - rule->getTemplateSpecializationArgs()->asArray(); - clang::TemplateArgumentListInfo explicitTArgs; - - { - const clang::Sema::InstantiatingTemplate Inst(*sema_, loc_, decl); - assert(!Inst.isInvalid() && "Invalid instantiation context"); - for (const auto &argloc : lookup.explicitArgs) { - const auto &arg = argloc.getArgument(); - if (!arg.isDependent()) { - explicitTArgs.addArgument(argloc); - continue; - } - - clang::TemplateArgument inst; - if (arg.getKind() == clang::TemplateArgument::Type) { - inst = clang::TemplateArgument( - getSubstType(Inst, arg.getAsType(), ruleTArgs)); - } else if (arg.getKind() == clang::TemplateArgument::Expression) { - if (auto *expr = - llvm::dyn_cast(arg.getAsExpr())) { - const auto *nttp = - llvm::dyn_cast(expr->getDecl()); - assert(nttp && "Unexpected decl in expr"); - inst = ruleTArgs[nttp->getIndex()]; - } else { - assert(0 && "Unsupported explicit template argument expression"); - } - } else { - assert(0 && "Unsupported explicit template argument kind"); - } - - explicitTArgs.addArgument( - sema_->getTrivialTemplateArgumentLoc(inst, {}, loc_)); - } - } - - clang::DeclarationName name = lookup.name; - if (clang::QualType nameType = name.getCXXNameType(); - !nameType.isNull() && nameType->isDependentType()) { - const clang::Sema::InstantiatingTemplate Inst(*sema_, loc_, decl); - assert(!Inst.isInvalid() && "Invalid instantiation context"); - clang::MultiLevelTemplateArgumentList mtal; - mtal.setKind(clang::TemplateSubstitutionKind::Rewrite); - mtal.addOuterTemplateArguments(ruleTArgs); - name = sema_->SubstDeclarationNameInfo({name, loc_}, mtal).getName(); - } - - clang::OverloadCandidateSet candidates(loc_, csk); - switch (lookup.kind) { - case LookupKind::RegularName: - regularNameLookup(callArgs, &explicitTArgs, name, candidates); - break; - case LookupKind::CXXMethodName: { - llvm::ArrayRef margs = callArgs; - cxxMethodNameLookup(margs.front()->getType().getNonReferenceType(), - margs.drop_front(), &explicitTArgs, name, candidates); - break; - } - case LookupKind::CXXConstructorName: - cxxConstructorNameLookup(rule->getReturnType(), callArgs, candidates); - break; - case LookupKind::ADL: - regularNameLookup(callArgs, &explicitTArgs, name, candidates); - adlLookup(callArgs, name, candidates); - break; - } - - clang::OverloadCandidateSet::iterator best; - switch (candidates.BestViableFunction(*sema_, loc_, best)) { - case clang::OverloadingResult::OR_Success: - return best->Function; - case clang::OverloadingResult::OR_Ambiguous: - for (auto &candidate : candidates) { - if (candidate.Viable) { - return candidate.Function; - } - } - break; - case clang::OverloadingResult::OR_No_Viable_Function: - llvm::errs() << "No viable function\n"; - break; - case clang::OverloadingResult::OR_Deleted: - llvm::errs() << "Deleted function selected\n"; - break; - } - - assert(0 && "Rule resolution failed"); - return nullptr; - } - - clang::NamedDecl *lookupMemberAccess(clang::FunctionTemplateDecl *decl, - clang::DeclarationName name) { - clang::NamespaceDecl *ns = createNamespaceDecl(); - clang::Sema::ContextRAII savedContext(*sema_, ns); - clang::FunctionDecl *rule = instantiateRuleDecl(decl); - assert(rule && "Rule instantiation failed"); - clang::CXXRecordDecl *rdecl = - resolveCXXRecordDecl(rule->getParamDecl(0)->getType()); - assert(rdecl && "Failed fetching record decl"); - clang::LookupResult members(*sema_, name, loc_, - clang::Sema::LookupMemberName); - sema_->LookupQualifiedName(members, rdecl); - assert(!members.empty() && "Rule resolution failed"); - return members.getRepresentativeDecl(); - } - - clang::MemberExpr * - lookupArrowAccess(clang::FunctionTemplateDecl *decl, - const clang::DeclarationNameInfo &nameInfo, - clang::NestedNameSpecifierLoc nns) { - clang::NamespaceDecl *ns = createNamespaceDecl(); - clang::Sema::ContextRAII savedContext(*sema_, ns); - clang::FunctionDecl *rule = instantiateRuleDecl(decl); - assert(rule && "Rule instantiation failed"); - - clang::Expr *obj = createOpaqueValueExpr( - rule->getParamDecl(0)->getType().getNonReferenceType()); - auto arrow = - sema_->BuildOverloadedArrowExpr(sema_->getCurScope(), obj, loc_); - assert(arrow.isUsable() && "Overloaded arrow operator not found"); - - auto *base = arrow.getAs(); - assert(base && "Unexpected base type"); - - clang::CXXRecordDecl *rdecl = - resolveCXXRecordDecl(base->getType()->getPointeeType()); - assert(rdecl && "Failed fetching record decl"); - - clang::LookupResult members(*sema_, nameInfo.getName(), loc_, - clang::Sema::LookupMemberName); - sema_->LookupQualifiedName(members, rdecl); - for (auto *ndecl : members) { - if (auto *vdecl = llvm::dyn_cast(ndecl)) { - clang::MemberExpr *access = sema_->BuildMemberExpr( - base, true, loc_, nns, loc_, vdecl, - clang::DeclAccessPair::make(vdecl, clang::AS_public), false, - nameInfo, vdecl->getType(), clang::VK_LValue, clang::OK_Ordinary); - assert(access && "Rule resolution failed"); - return access; - } - } - assert(0 && "Rule resolution failed"); - return nullptr; - } - - clang::QualType lookupType(clang::TypeAliasTemplateDecl *decl) { - clang::NamespaceDecl *ns = createNamespaceDecl(); - clang::Sema::ContextRAII savedContext(*sema_, ns); - - llvm::SmallVector args; + clang::QualType instantiateTypeRule(clang::TypeAliasTemplateDecl *decl) { + llvm::SmallVector args; createTemplateArguments(decl, args); - clang::MultiLevelTemplateArgumentList mtal; - mtal.setKind(clang::TemplateSubstitutionKind::Rewrite); - mtal.addOuterTemplateArguments(args); - - clang::Sema::InstantiatingTemplate TypeInst(*sema_, loc_, decl, args); - assert(!TypeInst.isInvalid() && "Invalid instantiation context"); + clang::QualType type = getTemplateIdType(decl, args); + assert(!type.isNull() && "Type rule instantiation failed"); - clang::TypeSourceInfo *tsi = - sema_->SubstType(decl->getTemplatedDecl()->getTypeSourceInfo(), mtal, - loc_, clang::DeclarationName()); - assert(tsi && "Rule resolution failed"); - return tsi->getType(); + const auto *tst = type->getAs(); + assert(tst && tst->isTypeAlias()); + return tst->getAliasedType(); } }; @@ -900,40 +315,16 @@ class ActionFactory : public clang::tooling::FrontendActionFactory { public: explicit ActionFactory(llvm::json::Object &out) : cb_(out) { using namespace clang::ast_matchers; - finder_.addMatcher( - returnStmt( - isExpansionInMainFile(), - hasReturnValue(ignoringImplicit(ignoringParenImpCasts(anyOf( - callExpr().bind("fcall"), cxxConstructExpr().bind("ctor"), - cxxFunctionalCastExpr(has(ignoringImplicit( - ignoringParenImpCasts(cxxConstructExpr().bind("ctor"))))), - memberExpr(hasDeclaration(fieldDecl())).bind("muse"), - unresolvedMemberExpr().bind("umuse"), - declRefExpr(to(anyOf(enumConstantDecl().bind("enum_val"), - decl(unless(parmVarDecl())).bind("decl")))) - .bind("declref"), - unaryOperator(hasUnaryOperand( - declRefExpr(to(decl(unless(parmVarDecl())))))) - .bind("udeclref"), - cxxDependentScopeMemberExpr().bind("dsme"), - cxxUnresolvedConstructExpr().bind("uctor"), - integerLiteral().bind("macro_int"))))), - hasAncestor(functionDecl(isDefinition(), - matchesName("(^|::)f[0-9]+$"), - isExpansionInMainFile()) - .bind("func"))), - &cb_); - finder_.addMatcher( typedefNameDecl(matchesName("(^|::)t[0-9]+$"), isExpansionInMainFile()) .bind("tvar"), &cb_); - finder_.addMatcher(functionDecl(isDefinition(), - matchesName("(^|::)f[0-9]+$"), - isExpansionInMainFile()) - .bind("validate_func"), - &cb_); + finder_.addMatcher( + functionDecl(isDefinition(), matchesName("(^|::)f[0-9]+$"), + isExpansionInMainFile(), unless(isTemplateInstantiation())) + .bind("func"), + &cb_); } std::unique_ptr create() override { @@ -948,10 +339,11 @@ class ActionFactory : public clang::tooling::FrontendActionFactory { if (DE.hasErrorOccurred()) { std::exit(EXIT_FAILURE); } - DE.setSuppressAllDiagnostics(true); - DE.setClient(new clang::IgnoringDiagConsumer(), true); CB_->init(CI_->getSema()); AC_->HandleTranslationUnit(ctx); + if (DE.hasErrorOccurred()) { + std::exit(EXIT_FAILURE); + } } private: @@ -1022,8 +414,13 @@ int main(int argc, char *argv[]) { llvm::cl::HideUnrelatedOptions(cat); llvm::cl::ParseCommandLineOptions(argc, argv); - llvm::SmallVector cxx_flags(CXXFlags.begin(), - CXXFlags.end()); + llvm::SmallVector cxx_flags = { + "-Wno-everything", + "-I", + RULES_LIB_INCLUDE_DIR, + }; + cxx_flags.append(CXXFlags.begin(), CXXFlags.end()); + fs::path dir = SrcDir.getValue(); llvm::json::Object root; for (const char *name : {"src.c", "src.cpp"}) { diff --git a/libcc2rs/src/iterators.rs b/libcc2rs/src/iterators.rs index 623a1110f..6065a0eb8 100644 --- a/libcc2rs/src/iterators.rs +++ b/libcc2rs/src/iterators.rs @@ -1,7 +1,10 @@ // Copyright (c) 2022-present INESC-ID. // Distributed under the MIT license that can be found in the LICENSE file. -use crate::{PostfixDec, PostfixInc, PrefixDec, PrefixInc, Ptr, Value}; +use crate::{ + PostfixDec, PostfixInc, PrefixDec, PrefixInc, Ptr, UnsafePostfixDec, UnsafePostfixInc, + UnsafePrefixDec, UnsafePrefixInc, Value, +}; use std::cell::RefCell; use std::collections::BTreeMap; use std::ops::Bound; @@ -225,3 +228,9 @@ impl> PostfixDec for MapIter Self; +} diff --git a/rule-preprocessor/src/syntactic.rs b/rule-preprocessor/src/syntactic.rs index 266613a0c..89625b4ad 100644 --- a/rule-preprocessor/src/syntactic.rs +++ b/rule-preprocessor/src/syntactic.rs @@ -381,11 +381,9 @@ impl<'a> FnIrBuilder<'a> { for pred in wc.predicates() { let Some(ty) = pred.ty() else { continue }; let name = ty.syntax().text().to_string(); - let bounds = extract_bounds(pred.type_bound_list()); - generics - .entry(name) - .and_modify(|existing| existing.extend(bounds.clone())) - .or_insert(bounds); + if let Some(generic) = generics.get_mut(&name) { + generic.extend(extract_bounds(pred.type_bound_list())); + } } } diff --git a/rules/algorithm/src.cpp b/rules/algorithm/src.cpp index 097b05cb1..a4056eb99 100644 --- a/rules/algorithm/src.cpp +++ b/rules/algorithm/src.cpp @@ -7,114 +7,52 @@ #include #include +#include "rule_hints.h" + struct T2 { friend bool operator<(T2 a, T2 b) { return false; } }; -struct T1 { - using value_type = T2; - using difference_type = std::ptrdiff_t; - using reference = T2 &; - using pointer = T2 *; - using iterator_category = std::random_access_iterator_tag; - - pointer p = nullptr; - - T1() = default; - - operator T2() const { return {}; } - - reference operator*() const { return *p; } - pointer operator->() const { return p; } - reference operator[](difference_type n) const { return p[n]; } - - T1 &operator++() { - ++p; - return *this; - } - T1 operator++(int) { - T1 tmp = *this; - ++*this; - return tmp; - } - T1 &operator--() { - --p; - return *this; - } - T1 operator--(int) { - T1 tmp = *this; - --*this; - return tmp; - } - - T1 &operator+=(difference_type n) { - p += n; - return *this; - } - T1 &operator-=(difference_type n) { - p -= n; - return *this; - } - friend T1 operator+(T1 it, difference_type n) { - it += n; - return it; - } - friend T1 operator+(difference_type n, T1 it) { - it += n; - return it; - } - friend T1 operator-(T1 it, difference_type n) { - it -= n; - return it; - } - friend difference_type operator-(T1 a, T1 b) { return a.p - b.p; } - - friend bool operator==(T1 a, T1 b) { return a.p == b.p; } - friend bool operator!=(T1 a, T1 b) { return a.p != b.p; } - friend bool operator<(T1 a, T1 b) { return a.p < b.p; } - friend bool operator>(T1 a, T1 b) { return a.p > b.p; } - friend bool operator<=(T1 a, T1 b) { return a.p <= b.p; } - friend bool operator>=(T1 a, T1 b) { return a.p >= b.p; } - - T1 &operator=(const T2 &rhs) { return *this; } -}; - -template void f1(T1 first, T1 last) { +template > void f1(T1 first, T1 last) { return std::sort(first, last); } -template T2 f2(T1 first, T1 last, T2 d_first) { +template , + typename T2 = Iterator> +T2 f2(T1 first, T1 last, T2 d_first) { return std::copy(first, last, d_first); } -template T1 f3(T1 first, T1 last, const T2 &value) { +template > +T1 f3(T1 first, T1 last, const T2 &value) { return std::find(first, last, value); } // TODO auto lambda = [](const T2 &a, const T2 &b) { return false; }; +template > void f6(T1 first, T1 last, decltype(lambda) comp) { return std::stable_sort(first, last, comp); } -template +template > void f7(T1 first, T1 last, bool (*comp)(const T2 &, const T2 &)) { 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 +template typename std::vector::iterator f10(typename std::vector::iterator a0, typename std::vector::iterator a1) { return std::unique(a0, a1); } -template +template void f12(typename std::vector::iterator a0, typename std::vector::iterator a1, const T2 &a2) { return std::fill(a0, a1, a2); @@ -128,19 +66,20 @@ std::ostream_iterator f13(std::string::iterator a0, // TODO auto lambda_nref = [](T2 a, T2 b) { return false; }; +template > void f14(T1 *first, T1 *last, decltype(lambda_nref) comp) { return std::stable_sort(first, last, comp); } -template +template void f15(T1 *first, T1 *last, bool (*comp)(T2, T2)) { return std::stable_sort(first, last, comp); } -template const T1 &f16(const T1 &a, const T1 &b) { +template const T1 &f16(const T1 &a, const T1 &b) { return std::min(a, b); } -template const T1 &f17(const T1 &a, const T1 &b) { +template const T1 &f17(const T1 &a, const T1 &b) { return std::max(a, b); } diff --git a/rules/array/src.cpp b/rules/array/src.cpp index 7c2cdcd24..209a10cd4 100644 --- a/rules/array/src.cpp +++ b/rules/array/src.cpp @@ -3,8 +3,7 @@ #include -template -using t1 = std::array; +template using t1 = std::array; template const T1 *f1(const std::array &o) { diff --git a/rules/cstddef/src.cpp b/rules/cstddef/src.cpp new file mode 100644 index 000000000..b1e15528a --- /dev/null +++ b/rules/cstddef/src.cpp @@ -0,0 +1,24 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include + +#include "rule_hints.h" + +using t1 = std::byte; + +template std::byte f1(const std::byte &a0, T1 a1) { + return operator<<(a0, a1); +} + +template std::byte f2(const std::byte &a0, T1 a1) { + return operator>>(a0, a1); +} + +template std::byte f3(std::byte &a0, T1 a1) { + return operator<<=(a0, a1); +} + +template std::byte f4(std::byte &a0, T1 a1) { + return operator>>=(a0, a1); +} diff --git a/rules/cstddef/tgt_unsafe.rs b/rules/cstddef/tgt_unsafe.rs new file mode 100644 index 000000000..afa758da0 --- /dev/null +++ b/rules/cstddef/tgt_unsafe.rs @@ -0,0 +1,38 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +fn t1() -> u8 { + Default::default() +} + +fn f1(a0: &mut u8, a1: T1) -> u8 +where + u8: std::ops::Shl, +{ + *a0 << a1 +} + +fn f2(a0: &mut u8, a1: T1) -> u8 +where + u8: std::ops::Shr, +{ + *a0 >> a1 +} + +fn f3(a0: &mut u8, a1: T1) -> u8 +where + u8: std::ops::Shl, +{ + let n_ = *a0 << a1; + *a0 = n_; + *a0 +} + +fn f4(a0: &mut u8, a1: T1) -> u8 +where + u8: std::ops::Shr, +{ + let n_ = *a0 >> a1; + *a0 = n_; + *a0 +} diff --git a/rules/iterator/src.cpp b/rules/iterator/src.cpp new file mode 100644 index 000000000..f18cb32cf --- /dev/null +++ b/rules/iterator/src.cpp @@ -0,0 +1,71 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include + +#include "rule_hints.h" + +template > +using t1 = std::reverse_iterator; + +template > +using t2 = typename std::reverse_iterator::difference_type; + +template > std::reverse_iterator f1() { + return std::reverse_iterator(); +} + +template > +std::reverse_iterator +f2(typename std::reverse_iterator::iterator_type a0) { + return std::reverse_iterator(a0); +} + +template > +typename std::reverse_iterator::iterator_type +f3(const std::reverse_iterator &a0) { + return a0.base(); +} + +template > +typename std::reverse_iterator::reference +f4(const std::reverse_iterator &a0) { + return a0.operator*(); +} + +template > +typename std::reverse_iterator::pointer +f5(const std::reverse_iterator &a0) { + return a0.operator->(); +} + +template > +std::reverse_iterator &f6(std::reverse_iterator &a0) { + return a0.operator++(); +} + +template > +std::reverse_iterator f7(std::reverse_iterator &a0, int a1) { + return a0.operator++(a1); +} + +template > +std::reverse_iterator +f8(const std::reverse_iterator &a0, + typename std::reverse_iterator::difference_type a1) { + return a0.operator+(a1); +} + +template > +std::reverse_iterator +f9(const std::reverse_iterator &a0, + typename std::reverse_iterator::difference_type a1) { + return a0.operator-(a1); +} + +template , + typename T2 = Iterator> +bool f10(const std::reverse_iterator &a0, + const std::reverse_iterator &a1) { + return operator==(a0, a1); +} diff --git a/rules/iterator/tgt_unsafe.rs b/rules/iterator/tgt_unsafe.rs new file mode 100644 index 000000000..862a76b21 --- /dev/null +++ b/rules/iterator/tgt_unsafe.rs @@ -0,0 +1,52 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +use libcc2rs::*; + +fn t1() -> T1 { + Default::default() +} + +fn t2() -> isize { + Default::default() +} + +fn f1() -> T1 { + Default::default() +} + +fn f2(a0: T1) -> T1 { + a0 +} + +fn f3(a0: T1) -> T1 { + a0 +} + +fn f4(a0: T1) -> T1 { + a0.offset(-1) +} + +fn f5(a0: T1) -> T1 { + a0.offset(-1) +} + +unsafe fn f6(mut a0: T1) -> T1 { + a0.prefix_dec() +} + +unsafe fn f7(mut a0: T1) -> T1 { + a0.postfix_dec() +} + +fn f8(a0: T1, a1: isize) -> T1 { + a0.offset(Into::::into(-a1)) +} + +fn f9(a0: T1, a1: isize) -> T1 { + a0.offset(Into::::into(a1)) +} + +fn f10(a0: T1, a1: T1) -> bool { + a0 == a1 +} diff --git a/rules/lib/rule_hints.h b/rules/lib/rule_hints.h new file mode 100644 index 000000000..2829d7450 --- /dev/null +++ b/rules/lib/rule_hints.h @@ -0,0 +1,462 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "rule_tags.h" + +namespace Synthesis { +template struct Slot; +using BindExisting = void; +using BindAny = void *; +} // namespace Synthesis + +#define ARG(...) __VA_ARGS__ + +#define DECLARE_HINT(name) template struct name + +#define DECLARE_PARAMETERIZABLE_HINT(name) \ + struct [[clang::annotate(CPP2RUST_PARAMETERIZABLE_RULE_TAG)]] name + +#define DECLARE_BUILTIN_HINT(name, type) \ + using name [[clang::annotate(CPP2RUST_BUILTIN_RULE_TAG)]] = type; + +#define DECLARE_PARAMETERIZABLE_BUILTIN_HINT(name, type) \ + using name [[clang::annotate(CPP2RUST_BUILTIN_RULE_TAG), \ + clang::annotate(CPP2RUST_PARAMETERIZABLE_RULE_TAG)]] = type; + +#define DECLARE_NON_TYPE_HINT(name, type, expr) constexpr type name = expr; + +DECLARE_BUILTIN_HINT(Integer, int) + +DECLARE_BUILTIN_HINT(Long, long) + +DECLARE_BUILTIN_HINT(Char, char) + +DECLARE_BUILTIN_HINT(WChar, wchar_t) + +DECLARE_BUILTIN_HINT(UnsignedInteger, unsigned) + +DECLARE_BUILTIN_HINT(ErrorCodeEnum, std::io_errc) + +DECLARE_BUILTIN_HINT(ErrorConditionEnum, std::errc) + +#if defined(__linux__) +DECLARE_BUILTIN_HINT(ExecutionPolicy, std::execution::parallel_policy) +#endif + +DECLARE_HINT(Plain){}; + +DECLARE_HINT(Comparable) { + template bool operator==(const Other &) const; + template bool operator!=(const Other &) const; + template bool operator<(const Other &) const; + template bool operator>(const Other &) const; + template bool operator<=(const Other &) const; + template bool operator>=(const Other &) const; +#if __cplusplus >= 202002L + template + std::strong_ordering operator<=>(const Other &) const; +#endif +}; + +DECLARE_HINT(MoveAssignable) { + template MoveAssignable &operator=(Other &&); + template MoveAssignable &operator=(Other &&) const; +}; + +DECLARE_HINT(NonConvertibleComparable) { + template bool operator==(const Other &) const; + template bool operator!=(const Other &) const; + template bool operator<(const Other &) const; + template bool operator>(const Other &) const; + template bool operator<=(const Other &) const; + template bool operator>=(const Other &) const; +#if __cplusplus >= 202002L + template + std::strong_ordering operator<=>(const Other &) const; +#endif +}; + +template struct is_non_convertible : std::false_type {}; + +template +struct is_non_convertible> : std::true_type {}; + +template +inline constexpr bool is_non_convertible_v = is_non_convertible::value; + +template +using enable_unless_non_convertible_t = std::enable_if_t>>>>; + +DECLARE_HINT(ExplicitlyConvertible) { + template > + explicit operator Other() const; +}; + +DECLARE_HINT(ImplicitlyConvertible) { + template > + operator Other() const; +}; + +template >> +DECLARE_PARAMETERIZABLE_BUILTIN_HINT(Variant, std::variant) + +template >, + typename T2 = Synthesis::Slot>> +DECLARE_PARAMETERIZABLE_BUILTIN_HINT(TupleLike, ARG(std::tuple)) + +DECLARE_HINT(StringLike) { + template > + operator std::basic_string() const; + + template > + operator std::basic_string_view() const; +}; + +template +using enable_any_convertible_t = + std::enable_if_t || + std::is_convertible_v>; + +template , ExplicitlyConvertible<>, + ImplicitlyConvertible<>, MoveAssignable<>>, + typename DiffT = Synthesis::Slot> +DECLARE_PARAMETERIZABLE_HINT(Iterator) { + using value_type = InnerT; + using difference_type = DiffT; + using pointer = value_type *; + using reference = value_type &; + using iterator_category = std::random_access_iterator_tag; +#if __cplusplus >= 202002L + using iterator_concept = std::contiguous_iterator_tag; +#endif + + reference operator*() const; + pointer operator->() const; + reference operator[](difference_type) const; + + Iterator &operator++(); + Iterator operator++(int) const; + Iterator &operator--(); + Iterator operator--(int) const; + + Iterator &operator+=(difference_type); + Iterator &operator-=(difference_type); + Iterator operator+(difference_type) const; + Iterator operator-(difference_type) const; + difference_type operator-(const Iterator &) const; + friend Iterator operator+(difference_type, const Iterator &); + + template , + typename = enable_any_convertible_t> + bool operator==(const Iterator &) const; + + template , + typename = enable_any_convertible_t> + bool operator!=(const Iterator &) const; + + template , + typename = enable_any_convertible_t> + bool operator<(const Iterator &) const; + + template , + typename = enable_any_convertible_t> + bool operator>(const Iterator &) const; + + template , + typename = enable_any_convertible_t> + bool operator<=(const Iterator &) const; + + template , + typename = enable_any_convertible_t> + bool operator>=(const Iterator &) const; + +#if __cplusplus >= 202002L + template , + typename = enable_any_convertible_t> + std::strong_ordering operator<=>(const Iterator &) const; +#endif + +#if defined(__linux__) + template >> + operator std::_Bit_const_iterator() const; + + template >> + operator std::_Bit_iterator() const; +#endif + + template , + typename = enable_any_convertible_t> + operator Iterator() const; +}; + +template , ExplicitlyConvertible<>, + ImplicitlyConvertible<>, MoveAssignable<>>, + typename DiffT = Synthesis::Slot> +DECLARE_PARAMETERIZABLE_HINT(InputIterator) { + using value_type = InnerT; + using difference_type = DiffT; + using pointer = const value_type *; + using reference = const value_type &; + using iterator_concept = std::input_iterator_tag; + using iterator_category = std::input_iterator_tag; + + reference operator*() const; + pointer operator->() const; + InputIterator &operator++(); + InputIterator operator++(int); + + template , + typename = enable_any_convertible_t> + bool operator==(const InputIterator &) const; + + template , + typename = enable_any_convertible_t> + bool operator!=(const InputIterator &) const; + + template , + typename = enable_any_convertible_t> + bool operator<(const InputIterator &) const; + + template , + typename = enable_any_convertible_t> + bool operator>(const InputIterator &) const; + + template , + typename = enable_any_convertible_t> + bool operator<=(const InputIterator &) const; + + template , + typename = enable_any_convertible_t> + bool operator>=(const InputIterator &) const; + +#if __cplusplus >= 202002L + template , + typename = enable_any_convertible_t> + std::strong_ordering operator<=>(const InputIterator &) + const; +#endif + + template , + typename = enable_any_convertible_t> + operator InputIterator() const; +}; + +DECLARE_HINT(Callable) { + using is_transparent = void; + + template int operator()(Args...) noexcept; + template int operator()(Args...) const noexcept; + + template + Return operator()(Args...) noexcept; + + template + Return operator()(Args...) const noexcept; + + template operator std::default_delete() const; +}; + +template >> +DECLARE_PARAMETERIZABLE_HINT(Allocator) { + using value_type = T; + + Allocator() noexcept; + template Allocator(const Allocator &) noexcept; + + T *allocate(std::size_t); + void deallocate(T *, std::size_t); + + template bool operator==(const Allocator &) const noexcept; + template bool operator!=(const Allocator &) const noexcept; +}; + +DECLARE_HINT(BoolConstant) { + static constexpr bool value = false; + using value_type = bool; + constexpr operator value_type() const noexcept { return value; } + constexpr value_type operator()() const noexcept { return value; } +}; + +template , ExplicitlyConvertible<>, + ImplicitlyConvertible<>, MoveAssignable<>>, + typename SizeT = Synthesis::Slot, + typename DiffT = Synthesis::Slot> +DECLARE_PARAMETERIZABLE_HINT(Container) { + using value_type = InnerT; + using size_type = SizeT; + using difference_type = DiffT; + using reference = value_type &; + using const_reference = const value_type &; + using iterator = Iterator; + using const_iterator = Iterator; + using reverse_iterator = Iterator; + using const_reverse_iterator = Iterator; + + reference operator[](size_type) const; + + void push_back(const value_type &); + void push_back(value_type &&); + void push_front(const value_type &); + void push_front(value_type &&); + + iterator insert(const_iterator, const InnerT &); + iterator insert(const_iterator, InnerT &&); + iterator insert(const_iterator, size_type, const InnerT &); + template iterator insert(const_iterator, InputIt, InputIt); + iterator insert(const_iterator, std::initializer_list); + + iterator begin() noexcept; + const_iterator begin() const noexcept; + const_iterator cbegin() const noexcept; + reverse_iterator rbegin() noexcept; + + iterator end() noexcept; + const_iterator end() const noexcept; + const_iterator cend() const noexcept; + reverse_iterator rend() noexcept; + + size_type size() const noexcept; + bool empty() const noexcept; + + reference front(); + reference back(); + reference at(size_type); + InnerT *data() noexcept; + + void clear() noexcept; + void pop_back(); + template reference emplace_back(Args && ...); + iterator erase(const_iterator); + void resize(size_type); +}; + +template , + typename IntT = Synthesis::Slot> +DECLARE_PARAMETERIZABLE_HINT(CharTraits) { + using char_type = CharT; + using int_type = IntT; + using off_type = std::streamoff; + using pos_type = std::streampos; + using state_type = std::mbstate_t; + + static void assign(char_type &, const char_type &); + static char_type *assign(char_type *, std::size_t, char_type); + + static bool eq(char_type, char_type); + static bool lt(char_type, char_type); + static int compare(const char_type *, const char_type *, std::size_t); + + static char_type *move(char_type *, const char_type *, std::size_t); + static char_type *copy(char_type *, const char_type *, std::size_t); + + static std::size_t length(const char_type *); + + static const char_type *find(const char_type *, std::size_t, + const char_type &); + + static char_type to_char_type(int_type); + static int_type to_int_type(char_type); + static bool eq_int_type(int_type, int_type); + + static int_type eof(); + static int_type not_eof(int_type); +}; + +template > +DECLARE_PARAMETERIZABLE_HINT(Range) { + T *begin(); + T *end(); + + const T *begin() const; + const T *end() const; +}; + +template > +DECLARE_PARAMETERIZABLE_HINT(Derived) : T{}; + +DECLARE_HINT(Mutex) { + void lock(); + void unlock(); + + bool try_lock(); + template bool try_lock_for(Duration); + template bool try_lock_until(Duration); +}; + +template , + typename ExternT = Synthesis::Slot> +DECLARE_PARAMETERIZABLE_HINT(Facet) + : public std::codecvt{}; + +template > +DECLARE_PARAMETERIZABLE_HINT(NumberGenerator) { + using result_type = T; + static constexpr result_type min() { return T{}; } + static constexpr result_type max() { return T{}; } + result_type operator()(); +}; + +template >> +DECLARE_PARAMETERIZABLE_BUILTIN_HINT(Const, const T) + +template > +DECLARE_PARAMETERIZABLE_BUILTIN_HINT(Pointer, T *) + +template >> +DECLARE_PARAMETERIZABLE_BUILTIN_HINT(Array, T[]) + +template > +DECLARE_PARAMETERIZABLE_BUILTIN_HINT(DefaultDelete, std::default_delete) + +DECLARE_NON_TYPE_HINT(NonNullInteger, int, 1) + +#if __cplusplus >= 202002L + DECLARE_NON_TYPE_HINT(SizedSubRangeKind, std::ranges::subrange_kind, + std::ranges::subrange_kind::sized) +#endif + +#define Plain Plain<__COUNTER__> +#define Comparable Comparable<__COUNTER__> +#define MoveAssignable MoveAssignable<__COUNTER__> +#define NonConvertibleComparable NonConvertibleComparable<__COUNTER__> +#define ExplicitlyConvertible ExplicitlyConvertible<__COUNTER__> +#define ImplicitlyConvertible ImplicitlyConvertible<__COUNTER__> +#define StringLike StringLike<__COUNTER__> +#define Callable Callable<__COUNTER__> +#define BoolConstant BoolConstant<__COUNTER__> +#define Mutex Mutex<__COUNTER__> diff --git a/rules/lib/rule_tags.h b/rules/lib/rule_tags.h new file mode 100644 index 000000000..7cfeb8a64 --- /dev/null +++ b/rules/lib/rule_tags.h @@ -0,0 +1,5 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#define CPP2RUST_PARAMETERIZABLE_RULE_TAG "cpp2rust::parameterizable_rule_hint" +#define CPP2RUST_BUILTIN_RULE_TAG "cpp2rust::builtin_rule_hint" diff --git a/rules/map/src.cpp b/rules/map/src.cpp index 2ab0aa1ab..a1b7e4f49 100644 --- a/rules/map/src.cpp +++ b/rules/map/src.cpp @@ -4,6 +4,8 @@ #include #include +#include "rule_hints.h" + template using t1 = std::map; template @@ -12,7 +14,8 @@ using t2 = typename std::map::const_iterator; template using t3 = typename std::map::iterator; -template T2 &f1(std::map &o, const T1 &key) { +template +T2 &f1(std::map &o, const T1 &key) { return o.operator[](key); } @@ -35,11 +38,13 @@ std::map f6(const std::map &&o) { return std::map(std::move(o)); } -template T2 &f7(std::map &o, const T1 &key) { +template +T2 &f7(std::map &o, const T1 &key) { return o.at(key); } -template T2 &f8(std::map &o, T1 &&key) { +template +T2 &f8(std::map &o, T1 &&key) { return o.operator[](std::move(key)); } @@ -48,7 +53,7 @@ typename std::map::const_iterator f9(const std::map &o) { return o.end(); } -template +template typename std::map::iterator f10(std::map &o, const T1 &key) { return o.find(key); } @@ -75,7 +80,7 @@ typename std::map::iterator f14(std::map &o) { return o.end(); } -template +template const T2 &f15(const std::map &o, const T1 &key) { return o.at(key); } @@ -86,7 +91,7 @@ bool f16(typename std::map::iterator a, return operator==(a, b); } -template +template typename std::map::const_iterator f17(const std::map &o, const T1 &key) { return o.find(key); diff --git a/rules/pair/src.cpp b/rules/pair/src.cpp index 24d4ec4c4..786d96968 100644 --- a/rules/pair/src.cpp +++ b/rules/pair/src.cpp @@ -3,6 +3,8 @@ #include +#include "rule_hints.h" + template using t1 = std::pair; template T2 &f1(std::pair &o) { @@ -19,17 +21,20 @@ std::pair f4(const T1 &a0, const T2 &a1) { return std::pair(a0, a1); } -template +template std::pair f5(const T3 &a0, T4 &a1) { return std::pair(a0, a1); } -template +template std::pair f6(T3 &a0, T4 &a1) { return std::pair(a0, a1); } -template +template std::pair f7(T3 &&a0, T4 &&a1) { return std::pair(std::move(a0), std::move(a1)); } diff --git a/rules/src/modules.rs b/rules/src/modules.rs index f4404a32b..fbe42be0c 100644 --- a/rules/src/modules.rs +++ b/rules/src/modules.rs @@ -28,6 +28,8 @@ pub mod carray_tgt_refcount; pub mod carray_tgt_unsafe; #[path = r#"../cmath/tgt_unsafe.rs"#] pub mod cmath_tgt_unsafe; +#[path = r#"../cstddef/tgt_unsafe.rs"#] +pub mod cstddef_tgt_unsafe; #[path = r#"../cstdlib/tgt_refcount.rs"#] pub mod cstdlib_tgt_refcount; #[path = r#"../cstdlib/tgt_unsafe.rs"#] @@ -86,6 +88,8 @@ pub mod iostream_tgt_unsafe; pub mod ip_tgt_refcount; #[path = r#"../ip/tgt_unsafe.rs"#] pub mod ip_tgt_unsafe; +#[path = r#"../iterator/tgt_unsafe.rs"#] +pub mod iterator_tgt_unsafe; #[path = r#"../limits/tgt_unsafe.rs"#] pub mod limits_tgt_unsafe; #[path = r#"../locale/tgt_refcount.rs"#] diff --git a/rules/unique_ptr/src.cpp b/rules/unique_ptr/src.cpp index acc6b05ae..9963f7141 100644 --- a/rules/unique_ptr/src.cpp +++ b/rules/unique_ptr/src.cpp @@ -4,6 +4,8 @@ #include #include +#include "rule_hints.h" + template using t1 = std::unique_ptr; template using t2 = std::unique_ptr; @@ -40,7 +42,8 @@ template T1 *f7(std::unique_ptr &o) { return o.get(); } // versions for make_unique with 1, 2, 3, etc arguments and translate the // specialized versions. -template std::unique_ptr f8(T2 &&a0) { +template +std::unique_ptr f8(T2 &&a0) { return std::make_unique(std::move(a0)); } diff --git a/rules/vector/src.cpp b/rules/vector/src.cpp index 2abb52cd8..a7ad4fcac 100644 --- a/rules/vector/src.cpp +++ b/rules/vector/src.cpp @@ -5,18 +5,20 @@ #include #include +#include "rule_hints.h" + template using t1 = std::vector; template using t2 = typename std::vector::iterator; template using t3 = std::vector>; template using t4 = typename std::vector::const_iterator; -template > +template > using t5 = std::vector; #if defined(__linux__) -template > +template > using t6 = typename std::vector::iterator; -template > +template > using t7 = typename std::vector::const_iterator; #endif @@ -181,7 +183,8 @@ std::vector f36(const std::initializer_list &a0) { return std::vector(a0); } -template std::vector f37(T2 *first, T2 *last) { +template +std::vector f37(T2 *first, T2 *last) { return std::vector(first, last); } @@ -189,7 +192,8 @@ std::vector f38(std::size_t n, const bool &value) { return std::vector(n, value); } -template const T1 *f40(T1 const (&a0)[T2]) { +template +const T1 *f40(T1 const (&a0)[T2]) { return std::end(a0); } @@ -197,7 +201,7 @@ template const T1 *f41(const std::vector &o) { return o.data(); } -template +template typename std::vector::const_iterator f42(typename std::vector::const_iterator first, typename std::vector::const_iterator last) { @@ -214,7 +218,9 @@ typename std::vector::const_iterator f44(const std::vector &o) { return o.end(); } -bool f47(std::vector &o) { return o[0]; } +bool f47(std::vector &a0, std::vector::size_type a1) { + return a0[a1].operator bool(); +} template void f48(std::vector &o, std::vector &a0) { return o.swap(a0); @@ -270,260 +276,260 @@ template void f59(std::vector &o) { return o.shrink_to_fit(); } -template > +template > typename std::vector::iterator f60(std::vector &o, typename std::vector::const_iterator it) { return o.erase(it); } -template > +template > std::size_t f61(const std::vector &o) { return o.size(); } -template > +template > bool f62(const std::vector &o) { return o.empty(); } -template > -std::vector f63() { +template > std::vector f63() { return std::vector(); } -template > +template > void f64(std::vector &o) { return o.pop_back(); } -template > +template > T1 *f65(std::vector &o) { return o.data(); } -template > +template > T1 &f66(std::vector &o, std::size_t idx) { return o.at(idx); } -template > +template > std::vector f67(std::size_t n) { return std::vector(n); } -template > +template > T1 &f68(std::vector &o) { return o.front(); } -template > +template > T1 &f69(std::vector &o) { return o.back(); } -template > +template > std::size_t f70(const std::vector &o) { return o.capacity(); } -template > +template > void f71(std::vector &o, std::size_t n) { return o.reserve(n); } -template > +template > typename std::vector::iterator f72(std::vector &o) { return o.begin(); } -template > +template > void f73(std::vector &o, T1 &&value) { return o.push_back(std::move(value)); } -template > +template > void f74(std::vector &o, std::size_t n) { return o.resize(n); } -template > +template > void f75(std::vector &o) { return o.clear(); } -template > +template > typename std::vector::iterator f76(std::vector &o) { return o.end(); } -template > +template > typename std::vector::iterator f77(std::vector &o, typename std::vector::const_iterator it, T1 &&value) { return o.insert(it, std::move(value)); } -template > +template > std::vector f78(std::size_t n, const T1 &value) { return std::vector(n, value); } -template > +template > typename std::vector::iterator f79(std::vector &o, typename std::vector::const_iterator it, const T1 &value) { return o.insert(it, value); } -template > +template > void f80(std::vector &o, const T1 &value) { return o.push_back(value); } -template > +template > typename std::vector::reference f81(typename std::vector::iterator it) { return it.operator*(); } -template > +template > typename std::vector::iterator f82(const typename std::vector::iterator &it) { return typename std::vector::iterator(it); } -template > +template > typename std::vector::const_iterator f83(const typename std::vector::iterator &it) { return typename std::vector::const_iterator(it); } -template > +template > typename std::vector::iterator f84(typename std::vector::iterator it, std::size_t n) { return it.operator+(n); } -template > +template > bool f85(const typename std::vector::iterator &it1, const typename std::vector::iterator &it2) { return operator!=(it1, it2); } -template > +template > bool f86(const typename std::vector::iterator &it1, const typename std::vector::iterator &it2) { return operator==(it1, it2); } -template > +template > typename std::vector::iterator f87(typename std::vector::iterator a0, int a1) { return a0.operator++(a1); } -template > +template > typename std::vector::iterator::difference_type f88(const typename std::vector::iterator &it1, const typename std::vector::iterator &it2) { return operator-(it1, it2); } -template > +template > typename std::vector::iterator & f89(typename std::vector::iterator &it) { return it.operator++(); } -template > +template > std::vector f90(const T1 *first, const T1 *last) { return std::vector(first, last); } -template > +template > std::vector f91(const std::initializer_list &a0) { return std::vector(a0); } -template , typename T3> +template , + typename T3 = ImplicitlyConvertible> std::vector f92(T3 *first, T3 *last) { return std::vector(first, last); } -template > +template > const T1 *f93(const std::vector &o) { return o.data(); } -template > +template > typename std::vector::const_iterator f94(typename std::vector::const_iterator first, typename std::vector::const_iterator last) { return std::max_element(first, last); } -template > +template > typename std::vector::const_iterator f95(const std::vector &o) { return o.begin(); } -template > +template > typename std::vector::const_iterator f96(const std::vector &o) { return o.end(); } -template > +template > void f97(std::vector &o, std::vector &a0) { return o.swap(a0); } -template > +template > const T1 &f98(const std::vector &o, std::size_t idx) { return o.at(idx); } -template > +template > const T1 &f99(const std::vector &o) { return o.back(); } -template > +template > void f100(std::vector> &o, const std::vector &value) { return o.push_back(value); } -template > +template > typename std::vector::iterator f101(std::vector &o, typename std::vector::const_iterator pos, const T1 *first, const T1 *last) { return o.insert(pos, first, last); } -template > +template > void f102(std::vector &o, std::size_t n, const typename std::vector::value_type &value) { return o.resize(n, value); } -template > +template > std::vector &f103(std::vector &dst, std::vector &&src) { return dst.operator=(std::move(src)); } -template > +template > typename std::vector::const_iterator f104(const std::vector &o) { return o.cend(); } -template > +template > std::vector &f105(std::vector &dst, const std::vector &src) { return dst.operator=(src); } -template > +template > void f106(std::vector &o) { return o.shrink_to_fit(); } diff --git a/tests/unit/byte.cpp b/tests/unit/byte.cpp new file mode 100644 index 000000000..a75caa584 --- /dev/null +++ b/tests/unit/byte.cpp @@ -0,0 +1,44 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include +#include + +int main() { + std::byte b1{0x01}; + + int ishift1 = 3; + std::byte shl1 = b1 << ishift1; + assert(shl1 == std::byte(0x08)); + + int ishift2 = 2; + std::byte shr1 = shl1 >> ishift2; + assert(shr1 == std::byte(0x02)); + + int ishift3 = 5; + b1 <<= ishift3; + assert(b1 == std::byte(0x20)); + + int ishift4 = 3; + b1 >>= ishift4; + assert(b1 == std::byte(0x04)); + + std::byte b2{0x01}; + + unsigned ushift1 = 3; + std::byte shl2 = b2 << ushift1; + assert(shl2 == std::byte(0x08)); + + unsigned ushift2 = 2; + std::byte shr2 = shl2 >> ushift2; + assert(shr2 == std::byte(0x02)); + + unsigned ushift3 = 5; + b2 <<= ushift3; + assert(b2 == std::byte(0x20)); + + unsigned ushift4 = 3; + b2 >>= ushift4; + assert(b2 == std::byte(0x04)); + return 0; +} diff --git a/tests/unit/out/refcount/byte.rs b/tests/unit/out/refcount/byte.rs new file mode 100644 index 000000000..9c7a4288f --- /dev/null +++ b/tests/unit/out/refcount/byte.rs @@ -0,0 +1,56 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let b1: Value = Rc::new(RefCell::new(1_u8)); + let ishift1: Value = Rc::new(RefCell::new(3)); + let shl1: Value = Rc::new(RefCell::new((*b1.borrow()) << (*ishift1.borrow()))); + assert!(((*shl1.borrow()) == 8)); + let ishift2: Value = Rc::new(RefCell::new(2)); + let shr1: Value = Rc::new(RefCell::new((*shl1.borrow()) >> (*ishift2.borrow()))); + assert!(((*shr1.borrow()) == 2)); + let ishift3: Value = Rc::new(RefCell::new(5)); + { + let n_ = (*b1.borrow()) << (*ishift3.borrow()); + (*b1.borrow_mut()) = n_; + (*b1.borrow()) + }; + assert!(((*b1.borrow()) == 32)); + let ishift4: Value = Rc::new(RefCell::new(3)); + { + let n_ = (*b1.borrow()) >> (*ishift4.borrow()); + (*b1.borrow_mut()) = n_; + (*b1.borrow()) + }; + assert!(((*b1.borrow()) == 4)); + let b2: Value = Rc::new(RefCell::new(1_u8)); + let ushift1: Value = Rc::new(RefCell::new(3_u32)); + let shl2: Value = Rc::new(RefCell::new((*b2.borrow()) << (*ushift1.borrow()))); + assert!(((*shl2.borrow()) == 8)); + let ushift2: Value = Rc::new(RefCell::new(2_u32)); + let shr2: Value = Rc::new(RefCell::new((*shl2.borrow()) >> (*ushift2.borrow()))); + assert!(((*shr2.borrow()) == 2)); + let ushift3: Value = Rc::new(RefCell::new(5_u32)); + { + let n_ = (*b2.borrow()) << (*ushift3.borrow()); + (*b2.borrow_mut()) = n_; + (*b2.borrow()) + }; + assert!(((*b2.borrow()) == 32)); + let ushift4: Value = Rc::new(RefCell::new(3_u32)); + { + let n_ = (*b2.borrow()) >> (*ushift4.borrow()); + (*b2.borrow_mut()) = n_; + (*b2.borrow()) + }; + assert!(((*b2.borrow()) == 4)); + return 0; +} diff --git a/tests/unit/out/refcount/reverse_iterator.rs b/tests/unit/out/refcount/reverse_iterator.rs new file mode 100644 index 000000000..0d1901683 --- /dev/null +++ b/tests/unit/out/refcount/reverse_iterator.rs @@ -0,0 +1,84 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +#[derive(Default)] +pub struct Foo { + pub v: Value, +} +impl Foo { + pub fn get(&self) -> i32 { + return (*self.v.borrow()); + } +} +impl Clone for Foo { + fn clone(&self) -> Self { + let mut this = Self { + v: Rc::new(RefCell::new((*self.v.borrow()))), + }; + this + } +} +impl ByteRepr for Foo { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.v.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + v: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let a1: Value> = Rc::new(RefCell::new(Box::new([ + Foo { + v: Rc::new(RefCell::new(10)), + }, + Foo { + v: Rc::new(RefCell::new(20)), + }, + Foo { + v: Rc::new(RefCell::new(30)), + }, + Foo { + v: Rc::new(RefCell::new(40)), + }, + Foo { + v: Rc::new(RefCell::new(50)), + }, + ]))); + let def: Value> = Rc::new(RefCell::new(Default::default())); + let first: Value> = Rc::new(RefCell::new( + (a1.as_pointer() as Ptr).offset((5) as isize), + )); + assert!(((*first.borrow()) == (a1.as_pointer() as Ptr).offset((5) as isize))); + let ref_: Ptr = (*first.borrow()).offset(-1); + assert!((({ (*ref_.upgrade().deref()).get() }) == 50)); + assert!((({ (*(*first.borrow()).offset(-1).upgrade().deref()).get() }) == 50)); + (*first.borrow_mut()).prefix_dec(); + assert!((({ (*(*first.borrow()).offset(-1).upgrade().deref()).get() }) == 40)); + let inc: Value> = Rc::new(RefCell::new((*first.borrow_mut()).postfix_dec())); + assert!((({ (*(*inc.borrow()).offset(-1).upgrade().deref()).get() }) == 40)); + assert!((({ (*(*first.borrow()).offset(-1).upgrade().deref()).get() }) == 30)); + let n: Value = Rc::new(RefCell::new(2_isize)); + let plus: Value> = Rc::new(RefCell::new( + (*first.borrow()).offset(Into::::into(-(*n.borrow()))), + )); + assert!((({ (*(*plus.borrow()).offset(-1).upgrade().deref()).get() }) == 10)); + let minus: Value> = Rc::new(RefCell::new( + (*plus.borrow()).offset(Into::::into((*n.borrow()))), + )); + assert!((({ (*(*minus.borrow()).offset(-1).upgrade().deref()).get() }) == 30)); + assert!((*minus.borrow()) == (*first.borrow())); + return 0; +} diff --git a/tests/unit/out/unsafe/byte.rs b/tests/unit/out/unsafe/byte.rs new file mode 100644 index 000000000..e3706e1dd --- /dev/null +++ b/tests/unit/out/unsafe/byte.rs @@ -0,0 +1,58 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut b1: u8 = 1_u8; + let mut ishift1: i32 = 3; + let mut shl1: u8 = b1 << ishift1; + assert!(((shl1) == (8))); + let mut ishift2: i32 = 2; + let mut shr1: u8 = shl1 >> ishift2; + assert!(((shr1) == (2))); + let mut ishift3: i32 = 5; + { + let n_ = b1 << ishift3; + b1 = n_; + b1 + }; + assert!(((b1) == (32))); + let mut ishift4: i32 = 3; + { + let n_ = b1 >> ishift4; + b1 = n_; + b1 + }; + assert!(((b1) == (4))); + let mut b2: u8 = 1_u8; + let mut ushift1: u32 = 3_u32; + let mut shl2: u8 = b2 << ushift1; + assert!(((shl2) == (8))); + let mut ushift2: u32 = 2_u32; + let mut shr2: u8 = shl2 >> ushift2; + assert!(((shr2) == (2))); + let mut ushift3: u32 = 5_u32; + { + let n_ = b2 << ushift3; + b2 = n_; + b2 + }; + assert!(((b2) == (32))); + let mut ushift4: u32 = 3_u32; + { + let n_ = b2 >> ushift4; + b2 = n_; + b2 + }; + assert!(((b2) == (4))); + return 0; +} diff --git a/tests/unit/out/unsafe/reverse_iterator.rs b/tests/unit/out/unsafe/reverse_iterator.rs new file mode 100644 index 000000000..bf25012ef --- /dev/null +++ b/tests/unit/out/unsafe/reverse_iterator.rs @@ -0,0 +1,50 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct Foo { + pub v: i32, +} +impl Foo { + pub unsafe fn get(&self) -> i32 { + return self.v; + } +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut a1: [Foo; 5] = [ + Foo { v: 10 }, + Foo { v: 20 }, + Foo { v: 30 }, + Foo { v: 40 }, + Foo { v: 50 }, + ]; + let mut def: *mut Foo = Default::default(); + let mut first: *mut Foo = a1.as_mut_ptr().offset((5) as isize); + assert!(((first) == (a1.as_mut_ptr().offset((5) as isize)))); + let ref_: *mut Foo = &mut (*first.offset(-1)) as *mut Foo; + assert!(((unsafe { (*ref_).get() }) == (50))); + assert!(((unsafe { (*(first.offset(-1)).cast_const()).get() }) == (50))); + first.prefix_dec(); + assert!(((unsafe { (*(first.offset(-1)).cast_const()).get() }) == (40))); + let mut inc: *mut Foo = first.postfix_dec(); + assert!(((unsafe { (*(inc.offset(-1)).cast_const()).get() }) == (40))); + assert!(((unsafe { (*(first.offset(-1)).cast_const()).get() }) == (30))); + let mut n: isize = 2_isize; + let mut plus: *mut Foo = first.offset(Into::::into(-n)); + assert!(((unsafe { (*(plus.offset(-1)).cast_const()).get() }) == (10))); + let mut minus: *mut Foo = plus.offset(Into::::into(n)); + assert!(((unsafe { (*(minus.offset(-1)).cast_const()).get() }) == (30))); + assert!(minus == first); + return 0; +} diff --git a/tests/unit/reverse_iterator.cpp b/tests/unit/reverse_iterator.cpp new file mode 100644 index 000000000..c8ffdc111 --- /dev/null +++ b/tests/unit/reverse_iterator.cpp @@ -0,0 +1,38 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include +#include + +struct Foo { + int v; + int get() const { return v; } +}; + +int main() { + Foo a1[] = {{10}, {20}, {30}, {40}, {50}}; + + std::reverse_iterator def; + std::reverse_iterator first(a1 + 5); + assert(first.base() == a1 + 5); + + std::reverse_iterator::reference ref = *first; + assert(ref.get() == 50); + assert(first->get() == 50); + + ++first; + assert(first->get() == 40); + + std::reverse_iterator inc = first++; + assert(inc->get() == 40); + assert(first->get() == 30); + + std::reverse_iterator::difference_type n = 2; + + std::reverse_iterator plus = first + n; + assert(plus->get() == 10); + std::reverse_iterator minus = plus - n; + assert(minus->get() == 30); + assert(minus == first); + return 0; +}