diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 055db2e8ff..77196e05e4 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -5279,7 +5279,7 @@ Converter::ConvertInitFragment(clang::Expr *expr, if (!tgt_ir || !tgt_ir->usesInit()) { llvm::report_fatal_error("expression rule does not use Init"); } - auto type = RuleRegistry::GetInitType(expr); + auto type = RuleRegistry::GetInitType(ctx_, expr); Buffer buf(*this); PushExprKind push(*this, ExprKind::RValue); diff --git a/cpp2rust/converter/rules/expr_matcher.cpp b/cpp2rust/converter/rules/expr_matcher.cpp index 8365cbc7ae..2d51f91b68 100644 --- a/cpp2rust/converter/rules/expr_matcher.cpp +++ b/cpp2rust/converter/rules/expr_matcher.cpp @@ -275,6 +275,57 @@ void deduceMemberTypesFromOperands( } } +llvm::ArrayRef +getExplicitTemplateArgs(const clang::Expr *expr) { + auto call = llvm::dyn_cast(RuleDecls::SkipImplicit(expr)); + if (!call) { + return {}; + } + auto callee = call->getCallee()->IgnoreParenImpCasts(); + if (auto ref = llvm::dyn_cast(callee)) { + return ref->template_arguments(); + } + if (auto member = llvm::dyn_cast(callee)) { + return member->template_arguments(); + } + if (auto overload = llvm::dyn_cast(callee)) { + return overload->template_arguments(); + } + if (auto member = + llvm::dyn_cast(callee)) { + return member->template_arguments(); + } + return {}; +} + +void deduceFromExplicitArgs(clang::Sema &sema, + clang::FunctionTemplateDecl *rule, + const clang::Expr *use, + std::vector &deduced) { + auto rule_args = + getExplicitTemplateArgs(RuleDecls::GetReturned(rule->getTemplatedDecl())); + auto use_args = getExplicitTemplateArgs(use); + for (unsigned i = 0; i < rule_args.size() && i < use_args.size(); ++i) { + const auto &rule_arg = rule_args[i].getArgument(); + const auto &use_arg = use_args[i].getArgument(); + if (rule_arg.getKind() != clang::TemplateArgument::Type || + use_arg.getKind() != clang::TemplateArgument::Type) { + continue; + } + if (rule_arg.getAsType()->getAs()) { + break; + } + auto args = RuleDecls::DeduceFromType( + sema, rule->getTemplateParameters(), rule_arg.getAsType(), + use_arg.getAsType().getCanonicalType()); + for (unsigned j = 0; args && j < deduced.size(); ++j) { + if (deduced[j].isNull()) { + deduced[j] = (*args)[j]; + } + } + } +} + std::optional> deduceFromCallee(clang::Sema &sema, clang::FunctionTemplateDecl *rule, const clang::Expr *use) { @@ -343,6 +394,7 @@ clang::TemplateArgumentListInfo getResultArgs(clang::Sema &sema, } } deduceMemberTypesFromOperands(sema, rule, use, deduced); + deduceFromExplicitArgs(sema, rule, use, deduced); auto last = static_cast(deducible.find_last_unset()); for (unsigned i = 0; i < params->size() && i <= last; ++i) { auto param = params->getParam(i); diff --git a/cpp2rust/converter/rules/registry.cpp b/cpp2rust/converter/rules/registry.cpp index 974925fe40..f60397073b 100644 --- a/cpp2rust/converter/rules/registry.cpp +++ b/cpp2rust/converter/rules/registry.cpp @@ -60,31 +60,13 @@ bool pointsToUserType(clang::QualType type) { return tag && IsUserDefinedDecl(tag); } +constexpr llvm::StringLiteral kInitAliasPrefix = "cpp2rust_init_"; + bool isRuleName(llvm::StringRef name) { return name.size() > 1 && (name[0] == 'f' || name[0] == 't') && llvm::all_of(name.drop_front(), llvm::isDigit); } -// The T of a rule's trailing `Init &&...args` pack. -clang::QualType getInitPattern(const clang::FunctionDecl *rule) { - if (rule->param_empty()) { - return {}; - } - auto expansion = - rule->parameters().back()->getType()->getAs(); - if (!expansion) { - return {}; - } - auto alias = expansion->getPattern() - .getNonReferenceType() - ->getAs(); - if (!alias || !alias->isTypeAlias() || - alias->getTemplateName().getAsTemplateDecl()->getName() != "Init") { - return {}; - } - return alias->template_arguments()[0].getAsType(); -} - void collectGenerics(const std::vector &body, std::unordered_set &used) { TranslationRule::AnyFragment(body, [&](const TranslationRule::BodyFragment @@ -158,6 +140,7 @@ void checkGenerics(const std::string &dir, const std::string &name, for (const auto ¶m : rule.params) { collectGenerics(param.type, used); } + collectGenerics(rule.init.type, used); for (unsigned i : used) { if (!declared.contains(std::format("T{}", i)) && !isBoundArgument(rule, i)) { @@ -166,10 +149,14 @@ void checkGenerics(const std::string &dir, const std::string &name, llvm::report_fatal_error("Absent generic from src"); } } - if (rule.usesInit() && getInitPattern(decl).isNull()) { + if (rule.usesInit() && + (decl->param_empty() || !decl->parameters() + .back() + ->getType() + ->getAs())) { llvm::errs() << dir << "::" << name << '\n'; - llvm::report_fatal_error("Expr rule uses init but its src pack is not " - "declared as Init"); + llvm::report_fatal_error( + "Expr rule uses init but its src does not end in a pack"); } } @@ -219,6 +206,10 @@ void addCxxRules(clang::ASTContext &ctx, const clang::NamespaceDecl *rules) { } for (auto decl : ns->decls()) { auto named = llvm::cast(decl); + if (llvm::isa(named) && + named->getName().starts_with(kInitAliasPrefix)) { + continue; + } if (!isRuleName(named->getName())) { llvm::report_fatal_error("declaration is not a rule"); } @@ -451,18 +442,58 @@ clang::QualType GetConversionSourceType(clang::ASTContext &ctx, llvm::report_fatal_error("converted generic has no CppFrom bound"); } -clang::QualType GetInitType(const clang::Expr *expr) { +clang::QualType GetInitType(clang::ASTContext &ctx, const clang::Expr *expr) { auto match = findExpr(expr); assert(match.rule_decl && "expression must have a translation rule"); + const auto &rule = match.rule_decl->rule; + if (rule.init.cpp_type.empty()) { + llvm::StringRef type = rule.init.type; + unsigned n = 0; + [[maybe_unused]] bool bad = + !type.consume_front("T") || type.getAsInteger(10, n); + assert(!bad && "init type must be a bare generic or a cpp_type!"); + return GetGenericType(ctx, expr, n); + } auto function = match.rule_decl->decl->getAsFunction(); - auto pattern = getInitPattern(function); - assert(!pattern.isNull() && "rule has no Init pack"); - clang::MultiLevelTemplateArgumentList args( - function->getDescribedFunctionTemplate(), match.args, /*Final=*/false); + auto tmpl = function->getDescribedFunctionTemplate(); + assert(tmpl && "cpp_type! init in a non-template rule"); + clang::TypeAliasTemplateDecl *alias = nullptr; + for (auto decl : function->getDeclContext()->lookup( + &ctx.Idents.get(InitAliasName(model_, function->getName().str())))) { + if ((alias = llvm::dyn_cast(decl))) { + break; + } + } + assert(alias && "cpp_type! init has no alias next to its rule"); + clang::MultiLevelTemplateArgumentList args(tmpl, match.args, + /*Final=*/false); clang::Sema::InstantiatingTemplate inst( *sema_, expr->getBeginLoc(), const_cast(function)); - return sema_->SubstType(pattern, args, expr->getBeginLoc(), - clang::DeclarationName()); + auto type = + sema_->SubstType(alias->getTemplatedDecl()->getUnderlyingType(), args, + expr->getBeginLoc(), clang::DeclarationName()); + assert(!type.isNull() && "cpp_type! init does not substitute"); + return type; +} + +std::string InitCppType(Model model, const std::string &dir, + const std::string &name) { + auto rule = findRule(model, dir, name); + if (!rule) { + rule = findRule(Model::kUnsafe, dir, name); + } + if (!rule) { + return {}; + } + auto params = rule->getObject("params"); + auto init = params ? params->getObject("init") : nullptr; + auto cpp_type = init ? init->getString("cpp_type") : std::nullopt; + return cpp_type ? cpp_type->str() : std::string(); +} + +std::string InitAliasName(Model model, const std::string &name) { + return std::format("{}{}_{}", kInitAliasPrefix.str(), + model == Model::kRefCount ? "refcount" : "unsafe", name); } clang::QualType GetDeclaredReturnType(const clang::Expr *expr) { diff --git a/cpp2rust/converter/rules/registry.h b/cpp2rust/converter/rules/registry.h index cbe9905635..2c8a524be0 100644 --- a/cpp2rust/converter/rules/registry.h +++ b/cpp2rust/converter/rules/registry.h @@ -37,7 +37,12 @@ Matcher::Match Search(clang::ASTContext &ctx, const TranslationRule::ExprRule *GetExprRule(clang::ASTContext &ctx, const clang::Expr *expr); -clang::QualType GetInitType(const clang::Expr *expr); +clang::QualType GetInitType(clang::ASTContext &ctx, const clang::Expr *expr); + +std::string InitCppType(Model model, const std::string &dir, + const std::string &name); + +std::string InitAliasName(Model model, const std::string &name); clang::QualType GetGenericType(clang::ASTContext &ctx, const clang::Expr *expr, unsigned n); diff --git a/cpp2rust/converter/rules/rules_loader.cpp b/cpp2rust/converter/rules/rules_loader.cpp index 8e318b92c3..f8e0c96342 100644 --- a/cpp2rust/converter/rules/rules_loader.cpp +++ b/cpp2rust/converter/rules/rules_loader.cpp @@ -27,6 +27,7 @@ #include "converter/converter_lib.h" #include "converter/rules/decls.h" +#include "converter/rules/registry.h" #include "logging.h" namespace cpp2rust::RulesLoader { @@ -314,6 +315,16 @@ const llvm::json::Object &CxxIndex() { std::string WrapRule(const llvm::json::Object &rule, bool is_cxx) { auto dir = rule.getString("dir")->str(); auto text = rule.getString("text")->str(); + if (auto header = rule.getString("template_header")) { + auto name = rule.getString("name")->str(); + for (auto model : {Model::kUnsafe, Model::kRefCount}) { + auto cpp_type = RuleRegistry::InitCppType(model, dir, name); + if (!cpp_type.empty()) { + text += std::format("{} using {} = {};\n", header->str(), + RuleRegistry::InitAliasName(model, name), cpp_type); + } + } + } if (!is_cxx) { return std::format("#define {0} cpp2rust_rules_{1}_{0}\n{2}#undef {0}\n", rule.getString("name")->str(), dir, text); diff --git a/cpp2rust/converter/translation_rule.cpp b/cpp2rust/converter/translation_rule.cpp index f634a20aa4..66b6a6dabf 100644 --- a/cpp2rust/converter/translation_rule.cpp +++ b/cpp2rust/converter/translation_rule.cpp @@ -20,6 +20,8 @@ TypeInfo ParseTypeInfoJSON(const llvm::json::Object &obj) { TypeInfo info; if (auto ty = obj.getString("type")) info.type = ty->str(); + if (auto cpp_type = obj.getString("cpp_type")) + info.cpp_type = cpp_type->str(); if (auto v = obj.getBoolean("is_refcount_pointer")) info.is_refcount_pointer = *v; if (auto v = obj.getBoolean("is_unsafe_pointer")) @@ -296,6 +298,10 @@ ExprRule ParseExprRuleJSON(const llvm::json::Object &obj) { if (auto *params = obj.getObject("params")) { for (auto &[key, val] : *params) { if (auto *param_obj = val.getAsObject()) { + if (key == "init") { + ir.init = ParseTypeInfoJSON(*param_obj); + continue; + } size_t id = atoi(llvm::StringRef(key).data() + 1); ir.params.resize(std::max(ir.params.size(), id + 1)); ir.params[id] = ParseTypeInfoJSON(*param_obj); diff --git a/cpp2rust/converter/translation_rule.h b/cpp2rust/converter/translation_rule.h index 1bb3ae9d4c..9f08ea7d6d 100644 --- a/cpp2rust/converter/translation_rule.h +++ b/cpp2rust/converter/translation_rule.h @@ -92,6 +92,7 @@ bool AnyFragment(const std::vector &body, struct TypeInfo { std::vector derives; std::string type; + std::string cpp_type; bool is_refcount_pointer = false; bool is_unsafe_pointer = false; @@ -102,6 +103,7 @@ struct TypeInfo { struct ExprRule { std::vector params; + TypeInfo init; TypeInfo return_type; std::vector> generics; // "T1" -> [Ord, Clone] std::vector body; diff --git a/cpp2rust/rule_preprocessing/cpp_rule_indexer.cpp b/cpp2rust/rule_preprocessing/cpp_rule_indexer.cpp index 3ccf982258..6a7ba2e58c 100644 --- a/cpp2rust/rule_preprocessing/cpp_rule_indexer.cpp +++ b/cpp2rust/rule_preprocessing/cpp_rule_indexer.cpp @@ -78,7 +78,14 @@ void AddRequiredClasses(clang::QualType type, if (auto name = type->getAs()) { auto qualifier = name->getQualifier(); if (qualifier.getKind() == clang::NestedNameSpecifier::Kind::Type) { - AddRequiredClasses(clang::QualType(qualifier.getAsType(), 0), required); + if (auto spec = qualifier.getAsType() + ->getAs()) { + for (const auto &arg : spec->template_arguments()) { + if (arg.getKind() == clang::TemplateArgument::Type) { + AddRequiredClasses(arg.getAsType(), required); + } + } + } } return; } @@ -286,6 +293,14 @@ 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 tmpl = llvm::dyn_cast(decl)) { + rule["template_header"] = + clang::tooling::getText( + clang::CharSourceRange::getTokenRange( + tmpl->getTemplateParameters()->getSourceRange()), + ctx) + .str(); + } if (any_class) { rule["requires"] = llvm::json::Array{RulesLoader::kAnyIteratorKey}; } else if (auto required = RequiredClasses(decl, alias); diff --git a/libcc2rs/src/conversion.rs b/libcc2rs/src/conversion.rs index 946e6aee3d..61c26d57a8 100644 --- a/libcc2rs/src/conversion.rs +++ b/libcc2rs/src/conversion.rs @@ -35,3 +35,10 @@ impl CppFromUnsafe for T { unsafe { (*src).clone() } } } + +#[macro_export] +macro_rules! cpp_type { + ($cpp:literal, $rust:ty) => { + $rust + }; +} diff --git a/libcc2rs/src/reinterpret.rs b/libcc2rs/src/reinterpret.rs index 7759621f57..9e0ac16e00 100644 --- a/libcc2rs/src/reinterpret.rs +++ b/libcc2rs/src/reinterpret.rs @@ -175,6 +175,7 @@ impl ByteRepr for *const T {} impl ByteRepr for *mut T {} impl ByteRepr for (A, B) {} impl ByteRepr for std::collections::BTreeMap {} +impl ByteRepr for std::rc::Rc {} // Runs `f` with a zeroed scratch buffer of `len` elements. Small buffers live // on the stack so that accessing memory through a reinterpreted pointer does diff --git a/rule-preprocessor/src/ir.rs b/rule-preprocessor/src/ir.rs index 09014cd82b..cec8fe07c9 100644 --- a/rule-preprocessor/src/ir.rs +++ b/rule-preprocessor/src/ir.rs @@ -70,6 +70,8 @@ pub struct TypeInfo { pub is_unsafe_pointer: bool, #[serde(default, skip_serializing_if = "Vec::is_empty")] pub derives: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub cpp_type: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -121,7 +123,12 @@ impl FnIr { pub fn validate(&self, name: &str) { validate_consecutive_keys( - self.params.as_ref().map(|p| p.keys()).into_iter().flatten(), + self.params + .as_ref() + .map(|p| p.keys()) + .into_iter() + .flatten() + .filter(|key| *key != "init"), 'a', 0, &format!("Rule {name} params"), diff --git a/rule-preprocessor/src/syntactic.rs b/rule-preprocessor/src/syntactic.rs index 1441fc7ee6..f451e85dcf 100644 --- a/rule-preprocessor/src/syntactic.rs +++ b/rule-preprocessor/src/syntactic.rs @@ -4,9 +4,9 @@ use cfg_expr::Expression; use cfg_expr::expr::{Predicate, TargetPredicate}; use ra_ap_syntax::ast::{ - HasArgList, HasAttrs, HasGenericArgs, HasGenericParams, HasName, HasTypeBounds, + HasArgList, HasAttrs, HasGenericArgs, HasGenericParams, HasName, HasTypeBounds, IsString, }; -use ra_ap_syntax::{AstNode, SyntaxKind, ast, match_ast}; +use ra_ap_syntax::{AstNode, AstToken, SyntaxKind, ast, match_ast}; use std::collections::BTreeMap; use std::path::{Path, PathBuf}; @@ -42,6 +42,30 @@ fn pointer_flags(ty: &ast::Type) -> (bool, bool) { flags } +fn cpp_type_of(ty: &ast::Type) -> Option { + let ast::Type::MacroType(macro_type) = ty else { + return None; + }; + let call = macro_type.macro_call()?; + if call.path()?.segment()?.name_ref()?.text() != "cpp_type" { + return None; + } + let token = call + .token_tree()? + .syntax() + .descendants_with_tokens() + .filter_map(|element| element.into_token()) + .find(|token| token.kind() == SyntaxKind::STRING) + .expect("cpp_type! must start with a string literal"); + let string = ast::String::cast(token).expect("cpp_type! literal is not a string"); + let text = string.text_without_quotes(); + assert!( + !text.contains('\\'), + "cpp_type! literal must not contain escapes" + ); + Some(text.to_string()) +} + fn is_va_args_type(ty: &ast::Type) -> bool { if let ast::Type::PathType(boxed) = ty && let Some(segment) = boxed.path().and_then(|p| p.segment()) @@ -341,6 +365,7 @@ struct ParamInfo { is_mut_ref: bool, is_va_args: bool, is_init: bool, + cpp_type: Option, } struct FnIrBuilder<'a> { @@ -376,6 +401,11 @@ impl<'a> FnIrBuilder<'a> { "variadic argument parameter must be named `va`, found `{name}`" ); let is_init = name == "init"; + let cpp_type = cpp_type_of(&ty); + assert!( + cpp_type.is_none() || is_init, + "cpp_type! is only allowed as the type of `init`, found on `{name}`" + ); params.push(ParamInfo { name, ty: ty.syntax().text().to_string(), @@ -384,6 +414,7 @@ impl<'a> FnIrBuilder<'a> { is_mut_ref: matches!(&ty, ast::Type::RefType(r) if r.mut_token().is_some()), is_va_args, is_init, + cpp_type, }); } assert!( @@ -409,6 +440,7 @@ impl<'a> FnIrBuilder<'a> { is_refcount_pointer, is_unsafe_pointer, derives: Vec::new(), + cpp_type: None, }) } } @@ -616,7 +648,7 @@ impl<'a> FnIrBuilder<'a> { let params_map: BTreeMap = params .iter() - .filter(|p| !p.is_va_args && !p.is_init) + .filter(|p| !p.is_va_args) .map(|p| { ( p.name.clone(), @@ -625,6 +657,7 @@ impl<'a> FnIrBuilder<'a> { is_refcount_pointer: p.is_refcount_pointer, is_unsafe_pointer: p.is_unsafe_pointer, derives: Vec::new(), + cpp_type: p.cpp_type.clone(), }, ) }) @@ -735,6 +768,7 @@ impl<'a> TypeIrBuilder<'a> { is_refcount_pointer, is_unsafe_pointer, derives: Vec::new(), + cpp_type: None, }, } } diff --git a/rules/any/src_cxx23.cpp b/rules/any/src_cxx23.cpp new file mode 100644 index 0000000000..d1a55836c1 --- /dev/null +++ b/rules/any/src_cxx23.cpp @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +using t1 = std::any; + +std::any f1() { return std::any(); } + +void f6(std::any &a0) { return a0.reset(); } + +bool f8(const std::any &a0) { return a0.has_value(); } + +template +typename std::enable_if< + std::integral_constant< + bool, std::is_copy_constructible>::value && + std::is_constructible, T2...>::value>::value, + std::decay_t &>::type +f14(std::any &a0, T2 &&...a1) { + return a0.template emplace(std::forward(a1)...); +} + +template T1 *f19(std::any *a0) { return std::any_cast(a0); } + +template +std::enable_if_t< + std::is_constructible_v, T2...>, + std::any> +f27(T2 &&...a0) { + return std::make_any(std::forward(a0)...); +} diff --git a/rules/any/tgt_refcount.rs b/rules/any/tgt_refcount.rs new file mode 100644 index 0000000000..8bad9f113c --- /dev/null +++ b/rules/any/tgt_refcount.rs @@ -0,0 +1,40 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +use libcc2rs::*; +use std::cell::RefCell; +use std::rc::Rc; + +fn t1() -> Option> { + None +} + +fn f1() -> Option> { + None +} + +fn f6(a0: &mut Option>) { + *a0 = None +} + +fn f8(a0: Option>) -> bool { + a0.is_some() +} + +fn f14(a0: &mut Option>, init: cpp_type!("std::decay_t", T1)) -> Ptr { + let __value: Value = Rc::new(RefCell::new(init)); + let __ptr = __value.as_pointer(); + *a0 = Some(__value); + __ptr +} + +fn f19(a0: Ptr>>) -> Ptr { + a0.with(|__a: &Option>| match __a.clone().map(|__r| __r.downcast::>()) { + Some(Ok(__v)) => __v.as_pointer(), + _ => Ptr::null(), + }) +} + +fn f27(init: cpp_type!("std::decay_t", T1)) -> Option> { + Some(Rc::new(RefCell::new(init))) +} diff --git a/rules/any/tgt_unsafe.rs b/rules/any/tgt_unsafe.rs new file mode 100644 index 0000000000..dfdd9f82b1 --- /dev/null +++ b/rules/any/tgt_unsafe.rs @@ -0,0 +1,36 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +use libcc2rs::*; + +fn t1() -> Option> { + None +} + +unsafe fn f1() -> Option> { + None +} + +unsafe fn f6(a0: &mut Option>) { + *a0 = None +} + +unsafe fn f8(a0: Option>) -> bool { + a0.is_some() +} + +unsafe fn f14(a0: &mut Option>, init: cpp_type!("std::decay_t", T1)) -> &mut T1 { + *a0 = Some(Box::new(init)); + a0.as_mut().unwrap().downcast_mut::().unwrap() +} + +unsafe fn f19(a0: *mut Option>) -> *mut T1 { + match (*a0).as_mut().and_then(|__b| __b.downcast_mut::()) { + Some(__v) => __v as *mut T1, + None => std::ptr::null_mut(), + } +} + +unsafe fn f27(init: cpp_type!("std::decay_t", T1)) -> Option> { + Some(Box::new(init)) +} diff --git a/rules/common/init.h b/rules/common/init.h deleted file mode 100644 index 4d8d528716..0000000000 --- a/rules/common/init.h +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright (c) 2022-present INESC-ID. -// Distributed under the MIT license that can be found in the LICENSE file. - -template using Init = A; diff --git a/rules/deque/src.cpp b/rules/deque/src.cpp index 6fde4378ed..f7ffe33b8b 100644 --- a/rules/deque/src.cpp +++ b/rules/deque/src.cpp @@ -4,8 +4,6 @@ #include #include -#include "../common/init.h" - template using t1 = std::deque; template using t2 = typename std::deque::size_type; @@ -50,10 +48,10 @@ std::deque &f11(std::deque &dst, std::deque &&src) { return dst = std::move(src); } -template -auto f12(std::deque &o, Init &&...args) - -> decltype(o.emplace_back(std::forward(args)...)) { - return o.emplace_back(std::forward(args)...); +template +auto f12(std::deque &o, T2 &&...a1) + -> decltype(o.emplace_back(std::forward(a1)...)) { + return o.emplace_back(std::forward(a1)...); } template std::deque f14() { return std::deque(); } diff --git a/rules/iterator_category/src.cpp b/rules/iterator_category/src.cpp index 3895c49cdb..4d87690dcd 100644 --- a/rules/iterator_category/src.cpp +++ b/rules/iterator_category/src.cpp @@ -5,8 +5,6 @@ #include #include -#include "../common/init.h" - template < typename It, typename T1 = typename std::iterator_traits::value_type, typename = typename std::enable_if< diff --git a/rules/map/src.cpp b/rules/map/src.cpp index 5b492cde14..53ff394f75 100644 --- a/rules/map/src.cpp +++ b/rules/map/src.cpp @@ -109,3 +109,24 @@ template typename std::map::const_iterator f29(const std::map &o) { return o.begin(); } + +template +std::pair::iterator, bool> +f67(std::map &a0, T5 &&...a1) { + return a0.template emplace(std::forward(a1)...); +} + +template +typename std::map::iterator +f68(std::map &a0, + typename std::map::const_iterator a1, T5 &&...a2) { + return a0.template emplace_hint( + std::forward::const_iterator>(a1), + std::forward(a2)...); +} + +template +std::pair::iterator, bool> +f73(std::map &a0, const T1 &a1, T5 &&...a2) { + return a0.template try_emplace(a1, std::forward(a2)...); +} diff --git a/rules/map/tgt_refcount.rs b/rules/map/tgt_refcount.rs index a76ff4c160..e5121ea00c 100644 --- a/rules/map/tgt_refcount.rs +++ b/rules/map/tgt_refcount.rs @@ -2,6 +2,8 @@ // Distributed under the MIT license that can be found in the LICENSE file. use libcc2rs::*; +use std::cell::RefCell; +use std::rc::Rc; fn t1() -> Map, Value)> { Map::new() @@ -97,3 +99,53 @@ fn f28(a0: Ptr, Value fn f29(a0: Ptr, Value)>>) -> BidirectionalIterator<(Value, Value)> { a0.with(|__m: &Map, Value)>| __m.begin()) } + +fn f67( + a0: Ptr, Value)>>, + init: cpp_type!("typename std::map::value_type", (Value, Value)), +) -> (Value, Value)>>, Value) { + let __init = init; + let __key = __init.0.as_pointer(); + let __inserted = a0.with(|__m: &Map, Value)>| __m.get(&__key).is_none()); + if __inserted { + Map::subscript(a0.clone(), __key.clone()).write(__init.1.borrow().clone()); + } + ( + Rc::new(RefCell::new( + a0.with(|__m: &Map, Value)>| __m.find(&__key)), + )), + Rc::new(RefCell::new(__inserted)), + ) +} + +fn f68( + a0: Ptr, Value)>>, + a1: BidirectionalIterator<(Value, Value)>, + init: cpp_type!("typename std::map::value_type", (Value, Value)), +) -> BidirectionalIterator<(Value, Value)> { + let _ = a1; + let __init = init; + let __key = __init.0.as_pointer(); + if a0.with(|__m: &Map, Value)>| __m.get(&__key).is_none()) { + Map::subscript(a0.clone(), __key.clone()).write(__init.1.borrow().clone()); + } + a0.with(|__m: &Map, Value)>| __m.find(&__key)) +} + +fn f73( + a0: Ptr, Value)>>, + a1: Ptr, + init: T2, +) -> (Value, Value)>>, Value) { + let __key = a1; + let __inserted = a0.with(|__m: &Map, Value)>| __m.get(&__key).is_none()); + if __inserted { + Map::subscript(a0.clone(), __key.clone()).write(init); + } + ( + Rc::new(RefCell::new( + a0.with(|__m: &Map, Value)>| __m.find(&__key)), + )), + Rc::new(RefCell::new(__inserted)), + ) +} diff --git a/rules/map/tgt_unsafe.rs b/rules/map/tgt_unsafe.rs index 25f79b84a3..a2284bef3f 100644 --- a/rules/map/tgt_unsafe.rs +++ b/rules/map/tgt_unsafe.rs @@ -97,3 +97,41 @@ unsafe fn f28(a0: &mut UnsafeMap, a1: T1) -> usize { unsafe fn f29(a0: UnsafeMap) -> UnsafeBidirectionalIterator<(T1, T2)> { a0.begin() } + +unsafe fn f67( + a0: &mut UnsafeMap, + init: cpp_type!("typename std::map::value_type", (T1, T2)), +) -> (UnsafeBidirectionalIterator<(T1, T2)>, bool) { + let __init = init; + let __inserted = a0.get(&__init.0).is_none(); + if __inserted { + *a0.subscript(&__init.0) = __init.1; + } + (a0.find(&__init.0), __inserted) +} + +unsafe fn f68( + a0: &mut UnsafeMap, + a1: UnsafeBidirectionalIterator<(T1, T2)>, + init: cpp_type!("typename std::map::value_type", (T1, T2)), +) -> UnsafeBidirectionalIterator<(T1, T2)> { + let _ = a1; + let __init = init; + if a0.get(&__init.0).is_none() { + *a0.subscript(&__init.0) = __init.1; + } + a0.find(&__init.0) +} + +unsafe fn f73( + a0: &mut UnsafeMap, + a1: T1, + init: T2, +) -> (UnsafeBidirectionalIterator<(T1, T2)>, bool) { + let __key = a1; + let __inserted = a0.get(&__key).is_none(); + if __inserted { + *a0.subscript(&__key) = init; + } + (a0.find(&__key), __inserted) +} diff --git a/rules/unique_ptr/src.cpp b/rules/unique_ptr/src.cpp index 96705680bd..bdcb0a442f 100644 --- a/rules/unique_ptr/src.cpp +++ b/rules/unique_ptr/src.cpp @@ -4,8 +4,6 @@ #include #include -#include "../common/init.h" - template using t1 = std::unique_ptr; template using t2 = std::unique_ptr; template using t3 = typename std::unique_ptr::pointer; diff --git a/rules/unique_ptr/src_cxx14.cpp b/rules/unique_ptr/src_cxx14.cpp index e8a5d76b1b..6dcc186e11 100644 --- a/rules/unique_ptr/src_cxx14.cpp +++ b/rules/unique_ptr/src_cxx14.cpp @@ -5,13 +5,10 @@ #include #include -#include "../common/init.h" - template auto f1(std::size_t a0) { return std::make_unique(a0); } -template -std::unique_ptr f8(Init &&...args) { - return std::make_unique(std::forward(args)...); +template std::unique_ptr f8(T2 &&...a0) { + return std::make_unique(std::forward(a0)...); } diff --git a/rules/vector/src.cpp b/rules/vector/src.cpp index b132451153..05980fa9bc 100644 --- a/rules/vector/src.cpp +++ b/rules/vector/src.cpp @@ -8,8 +8,6 @@ #include #include -#include "../common/init.h" - template > using t5 = std::vector; @@ -241,10 +239,10 @@ std::vector f110(const std::vector &o) { return std::vector(o); } -template , typename... Args> -auto f114(std::vector &o, Init &&...args) - -> decltype(o.emplace_back(std::forward(args)...)) { - return o.emplace_back(std::forward(args)...); +template , typename... T3> +auto f114(std::vector &o, T3 &&...a1) + -> decltype(o.emplace_back(std::forward(a1)...)) { + return o.emplace_back(std::forward(a1)...); } template > diff --git a/tests/unit/any.cpp b/tests/unit/any.cpp new file mode 100644 index 0000000000..856fdfe7e8 --- /dev/null +++ b/tests/unit/any.cpp @@ -0,0 +1,28 @@ +// ADDITIONAL_COMPILE_FLAGS: -std=c++23 +#include +#include + +struct Point { + int x; + int y; + Point(int x, int y) : x(x), y(y) {} +}; + +int main() { + std::any a = std::make_any(3, 4); + assert(a.has_value()); + Point *p = std::any_cast(&a); + assert(p != nullptr); + assert(p->x == 3); + assert(p->y == 4); + assert(std::any_cast(&a) == nullptr); + Point &q = a.emplace(5, 6); + assert(q.x == 5); + assert(std::any_cast(&a)->y == 6); + std::any b = std::make_any(7); + assert(*std::any_cast(&b) == 7); + b.reset(); + assert(!b.has_value()); + assert(std::any_cast(&b) == nullptr); + return 0; +} diff --git a/tests/unit/map.cpp b/tests/unit/map.cpp index e696c65a29..caa288ecd8 100644 --- a/tests/unit/map.cpp +++ b/tests/unit/map.cpp @@ -5,6 +5,13 @@ void foo(unsigned x) { x = x + 1; } void bar(unsigned &x) { x = x + 1; } +struct Point { + int x; + int y; + Point() : x(0), y(0) {} + Point(int x, int y) : x(x), y(y) {} +}; + int main() { std::map m; m[0] = 1; @@ -106,6 +113,37 @@ int main() { assert(pair.second == pair.first % 2); last = pair.first; } + std::map m3; + auto inserted = m3.emplace(1, 2); + assert(inserted.second); + assert(inserted.first->second == 2); + auto not_inserted = m3.emplace(1, 3); + assert(!not_inserted.second); + assert(not_inserted.first->second == 2); + m3.emplace(std::make_pair(4, 5)); + assert(m3.size() == 2); + assert(m3[1] == 2); + assert(m3[4] == 5); + std::map::iterator hinted = m3.emplace_hint(m3.end(), 6, 7); + assert(hinted->second == 7); + int key1 = 1; + auto tried = m3.try_emplace(key1, 9); + assert(!tried.second); + assert(tried.first->second == 2); + int key8 = 8; + auto tried_new = m3.try_emplace(key8, 9); + assert(tried_new.second); + assert(m3[8] == 9); + assert(m3.size() == 4); + std::map points; + auto point_new = points.try_emplace(key1, 3, 4); + assert(point_new.second); + assert(points[1].x == 3); + assert(points[1].y == 4); + points.emplace(key8, Point(5, 6)); + assert(points[8].x == 5); + assert(points[8].y == 6); + assert(points.size() == 2); k = 0; const auto &value_0 = m.at(k); assert(m.size() + x1 + x2 + x3 + x4 + x5 + value_0 == 21); diff --git a/tests/unit/out/refcount/any.rs b/tests/unit/out/refcount/any.rs new file mode 100644 index 0000000000..ab2fec64fe --- /dev/null +++ b/tests/unit/out/refcount/any.rs @@ -0,0 +1,94 @@ +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(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)] +#[byte_size(8)] +pub struct Point { + #[offset(0)] + pub x: i32, + #[offset(4)] + pub y: i32, +} +impl Point { + pub fn new(mut x: i32, mut y: i32) -> Self { + Self { x: x, y: y } + } +} +pub fn main() { + __cpp2rust_init_globals(); + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let a: Value>> = Rc::new(RefCell::new(Some(Rc::new( + RefCell::new(Point::new({ 3 }, { 4 })), + )))); + assert!((*a.borrow()).is_some()); + let mut p: Ptr = (a.as_pointer()).with(|__a: &Option>| match __a + .clone() + .map(|__r| __r.downcast::>()) + { + Some(Ok(__v)) => __v.as_pointer(), + _ => Ptr::null(), + }); + assert!(!((p).is_null())); + assert!((p.with(|__s| __s.x) == 3)); + assert!((p.with(|__s| __s.y) == 4)); + assert!( + ((a.as_pointer()).with(|__a: &Option>| { + match __a.clone().map(|__r| __r.downcast::>()) { + Some(Ok(__v)) => __v.as_pointer(), + _ => Ptr::null(), + } + })) + .is_null() + ); + let q: Ptr = { + let __value: Value = Rc::new(RefCell::new(Point::new({ 5 }, { 6 }))); + let __ptr = __value.as_pointer(); + (*a.borrow_mut()) = Some(__value); + __ptr + }; + assert!((q.with(|__s| __s.x) == 5)); + assert!( + ((a.as_pointer()) + .with(|__a: &Option>| { + match __a.clone().map(|__r| __r.downcast::>()) { + Some(Ok(__v)) => __v.as_pointer(), + _ => Ptr::null(), + } + }) + .with(|__s| __s.y) + == 6) + ); + let b: Value>> = + Rc::new(RefCell::new(Some(Rc::new(RefCell::new(7))))); + assert!( + (((b.as_pointer()) + .with(|__a: &Option>| { + match __a.clone().map(|__r| __r.downcast::>()) { + Some(Ok(__v)) => __v.as_pointer(), + _ => Ptr::null(), + } + }) + .read()) + == 7) + ); + (*b.borrow_mut()) = None; + assert!(!((*b.borrow()).is_some())); + assert!( + ((b.as_pointer()).with(|__a: &Option>| { + match __a.clone().map(|__r| __r.downcast::>()) { + Some(Ok(__v)) => __v.as_pointer(), + _ => Ptr::null(), + } + })) + .is_null() + ); + return 0; +} +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/map.rs b/tests/unit/out/refcount/map.rs index 7031aac499..be71dc3b3d 100644 --- a/tests/unit/out/refcount/map.rs +++ b/tests/unit/out/refcount/map.rs @@ -12,6 +12,27 @@ pub fn foo_0(mut x: u32) { pub fn bar_1(x: Ptr) { x.write({ (x.read()).wrapping_add(1_u32) }); } +#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg)] +#[byte_size(8)] +pub struct Point { + #[offset(0)] + pub x: i32, + #[offset(4)] + pub y: i32, +} +impl Point { + pub fn new_1() -> Self { + Self { x: 0, y: 0 } + } + pub fn new_2(mut x: i32, mut y: i32) -> Self { + Self { x: x, y: y } + } +} +impl Default for Point { + fn default() -> Self { + { Point::new_1() } + } +} pub fn main() { __cpp2rust_init_globals(); std::process::exit(main_0()); @@ -486,6 +507,265 @@ fn main_0() -> i32 { ); last = (*(*pair.upgrade().deref()).0.borrow()); } + let m3: Value, Value)>> = Rc::new(RefCell::new(Map::new())); + let inserted: Value<( + Value, Value)>>, + Value, + )> = Rc::new(RefCell::new({ + let __init = (Rc::new(RefCell::new(1)), Rc::new(RefCell::new(2))); + let __key = __init.0.as_pointer(); + let __inserted = m3 + .as_pointer() + .with(|__m: &Map, Value)>| __m.get(&__key).is_none()); + if __inserted { + Map::subscript(m3.as_pointer().clone(), __key.clone()).write(__init.1.borrow().clone()); + } + ( + Rc::new(RefCell::new(m3.as_pointer().with( + |__m: &Map, Value)>| __m.find(&__key), + ))), + Rc::new(RefCell::new(__inserted)), + ) + })); + assert!(((*(*inserted.borrow()).1.borrow()) as bool)); + assert!( + ((*(*(*(*inserted.borrow()).0.borrow()) + .iter_deref() + .upgrade() + .deref()) + .1 + .borrow()) + == 2) + ); + let not_inserted: Value<( + Value, Value)>>, + Value, + )> = Rc::new(RefCell::new({ + let __init = (Rc::new(RefCell::new(1)), Rc::new(RefCell::new(3))); + let __key = __init.0.as_pointer(); + let __inserted = m3 + .as_pointer() + .with(|__m: &Map, Value)>| __m.get(&__key).is_none()); + if __inserted { + Map::subscript(m3.as_pointer().clone(), __key.clone()).write(__init.1.borrow().clone()); + } + ( + Rc::new(RefCell::new(m3.as_pointer().with( + |__m: &Map, Value)>| __m.find(&__key), + ))), + Rc::new(RefCell::new(__inserted)), + ) + })); + assert!(!(*(*not_inserted.borrow()).1.borrow())); + assert!( + ((*(*(*(*not_inserted.borrow()).0.borrow()) + .iter_deref() + .upgrade() + .deref()) + .1 + .borrow()) + == 2) + ); + { + let __init = { + let __a0 = (Rc::new(RefCell::new(4)), Rc::new(RefCell::new(5))); + ( + Rc::new(RefCell::new((__a0.0.as_pointer().read()))), + Rc::new(RefCell::new((__a0.1.as_pointer().read()))), + ) + }; + let __key = __init.0.as_pointer(); + let __inserted = m3 + .as_pointer() + .with(|__m: &Map, Value)>| __m.get(&__key).is_none()); + if __inserted { + Map::subscript(m3.as_pointer().clone(), __key.clone()).write(__init.1.borrow().clone()); + } + ( + Rc::new(RefCell::new(m3.as_pointer().with( + |__m: &Map, Value)>| __m.find(&__key), + ))), + Rc::new(RefCell::new(__inserted)), + ) + }; + assert!(((*m3.borrow()).len() == 2_usize)); + assert!( + ((Map::subscript_move( + m3.as_pointer(), + Rc::new(RefCell::new(1)).as_pointer(), + |__k| cpp_move!(__k) + ) + .read()) + == 2) + ); + assert!( + ((Map::subscript_move( + m3.as_pointer(), + Rc::new(RefCell::new(4)).as_pointer(), + |__k| cpp_move!(__k) + ) + .read()) + == 5) + ); + let hinted: Value, Value)>> = Rc::new(RefCell::new({ + let _ = , Value)>>::from( + m3.as_pointer() + .with(|__m: &Map, Value)>| __m.end()), + ); + let __init = (Rc::new(RefCell::new(6)), Rc::new(RefCell::new(7))); + let __key = __init.0.as_pointer(); + if m3 + .as_pointer() + .with(|__m: &Map, Value)>| __m.get(&__key).is_none()) + { + Map::subscript(m3.as_pointer().clone(), __key.clone()).write(__init.1.borrow().clone()); + } + m3.as_pointer() + .with(|__m: &Map, Value)>| __m.find(&__key)) + })); + assert!( + ((*(*(*hinted.borrow()).iter_deref().upgrade().deref()) + .1 + .borrow()) + == 7) + ); + let key1: Value = Rc::new(RefCell::new(1)); + let tried: Value<( + Value, Value)>>, + Value, + )> = Rc::new(RefCell::new({ + let __key = key1.as_pointer(); + let __inserted = m3 + .as_pointer() + .with(|__m: &Map, Value)>| __m.get(&__key).is_none()); + if __inserted { + Map::subscript(m3.as_pointer().clone(), __key.clone()).write(9); + } + ( + Rc::new(RefCell::new(m3.as_pointer().with( + |__m: &Map, Value)>| __m.find(&__key), + ))), + Rc::new(RefCell::new(__inserted)), + ) + })); + assert!(!(*(*tried.borrow()).1.borrow())); + assert!( + ((*(*(*(*tried.borrow()).0.borrow()) + .iter_deref() + .upgrade() + .deref()) + .1 + .borrow()) + == 2) + ); + let key8: Value = Rc::new(RefCell::new(8)); + let tried_new: Value<( + Value, Value)>>, + Value, + )> = Rc::new(RefCell::new({ + let __key = key8.as_pointer(); + let __inserted = m3 + .as_pointer() + .with(|__m: &Map, Value)>| __m.get(&__key).is_none()); + if __inserted { + Map::subscript(m3.as_pointer().clone(), __key.clone()).write(9); + } + ( + Rc::new(RefCell::new(m3.as_pointer().with( + |__m: &Map, Value)>| __m.find(&__key), + ))), + Rc::new(RefCell::new(__inserted)), + ) + })); + assert!(((*(*tried_new.borrow()).1.borrow()) as bool)); + assert!( + ((Map::subscript_move( + m3.as_pointer(), + Rc::new(RefCell::new(8)).as_pointer(), + |__k| cpp_move!(__k) + ) + .read()) + == 9) + ); + assert!(((*m3.borrow()).len() == 4_usize)); + let points: Value, Value)>> = Rc::new(RefCell::new(Map::new())); + let point_new: Value<( + Value, Value)>>, + Value, + )> = Rc::new(RefCell::new({ + let __key = key1.as_pointer(); + let __inserted = points + .as_pointer() + .with(|__m: &Map, Value)>| __m.get(&__key).is_none()); + if __inserted { + Map::subscript(points.as_pointer().clone(), __key.clone()) + .write(Point::new_2({ 3 }, { 4 })); + } + ( + Rc::new(RefCell::new(points.as_pointer().with( + |__m: &Map, Value)>| __m.find(&__key), + ))), + Rc::new(RefCell::new(__inserted)), + ) + })); + assert!(((*(*point_new.borrow()).1.borrow()) as bool)); + assert!( + (Map::subscript_move( + points.as_pointer(), + Rc::new(RefCell::new(1)).as_pointer(), + |__k| cpp_move!(__k) + ) + .with(|__s| __s.x) + == 3) + ); + assert!( + (Map::subscript_move( + points.as_pointer(), + Rc::new(RefCell::new(1)).as_pointer(), + |__k| cpp_move!(__k) + ) + .with(|__s| __s.y) + == 4) + ); + { + let __init = ( + Rc::new(RefCell::new((*key8.borrow()))), + Rc::new(RefCell::new(Point::new_2({ 5 }, { 6 }))), + ); + let __key = __init.0.as_pointer(); + let __inserted = points + .as_pointer() + .with(|__m: &Map, Value)>| __m.get(&__key).is_none()); + if __inserted { + Map::subscript(points.as_pointer().clone(), __key.clone()) + .write(__init.1.borrow().clone()); + } + ( + Rc::new(RefCell::new(points.as_pointer().with( + |__m: &Map, Value)>| __m.find(&__key), + ))), + Rc::new(RefCell::new(__inserted)), + ) + }; + assert!( + (Map::subscript_move( + points.as_pointer(), + Rc::new(RefCell::new(8)).as_pointer(), + |__k| cpp_move!(__k) + ) + .with(|__s| __s.x) + == 5) + ); + assert!( + (Map::subscript_move( + points.as_pointer(), + Rc::new(RefCell::new(8)).as_pointer(), + |__k| cpp_move!(__k) + ) + .with(|__s| __s.y) + == 6) + ); + assert!(((*points.borrow()).len() == 2_usize)); k = 0; let value_0: Ptr = ({ let __tmp_14: Value = Rc::new(RefCell::new((k as i16))); diff --git a/tests/unit/out/unsafe/any.rs b/tests/unit/out/unsafe/any.rs new file mode 100644 index 0000000000..abdb000c81 --- /dev/null +++ b/tests/unit/out/unsafe/any.rs @@ -0,0 +1,89 @@ +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, VaArg, FnPtrArg, Default)] +pub struct Point { + pub x: i32, + pub y: i32, +} +impl Point { + pub unsafe fn new(mut x: i32, mut y: i32) -> Self { + let mut this = Self { x: x, y: y }; + this + } +} +pub fn main() { + unsafe { + __cpp2rust_init_globals(); + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut a: Option> = Some(Box::new(Point::new({ 3 }, { 4 }))); + assert!(a.is_some()); + let mut p: *mut Point = match (*(&mut a as *mut Option>)) + .as_mut() + .and_then(|__b| __b.downcast_mut::()) + { + Some(__v) => __v as *mut Point, + None => std::ptr::null_mut(), + }; + assert!(!((p).is_null())); + assert!((((*p).x) == (3))); + assert!((((*p).y) == (4))); + assert!( + (match (*(&mut a as *mut Option>)) + .as_mut() + .and_then(|__b| __b.downcast_mut::()) + { + Some(__v) => __v as *mut i32, + None => std::ptr::null_mut(), + }) + .is_null() + ); + let q: *mut Point = { + a = Some(Box::new(Point::new({ 5 }, { 6 }))); + a.as_mut().unwrap().downcast_mut::().unwrap() + }; + assert!((((*q).x) == (5))); + assert!( + (((*match (*(&mut a as *mut Option>)) + .as_mut() + .and_then(|__b| __b.downcast_mut::()) + { + Some(__v) => __v as *mut Point, + None => std::ptr::null_mut(), + }) + .y) == (6)) + ); + let mut b: Option> = Some(Box::new(7)); + assert!( + ((*match (*(&mut b as *mut Option>)) + .as_mut() + .and_then(|__b| __b.downcast_mut::()) + { + Some(__v) => __v as *mut i32, + None => std::ptr::null_mut(), + }) == (7)) + ); + b = None; + assert!(!(b.is_some())); + assert!( + (match (*(&mut b as *mut Option>)) + .as_mut() + .and_then(|__b| __b.downcast_mut::()) + { + Some(__v) => __v as *mut i32, + None => std::ptr::null_mut(), + }) + .is_null() + ); + return 0; +} +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/map.rs b/tests/unit/out/unsafe/map.rs index a07f253dda..cb39347da8 100644 --- a/tests/unit/out/unsafe/map.rs +++ b/tests/unit/out/unsafe/map.rs @@ -12,6 +12,27 @@ pub unsafe fn foo_0(mut x: u32) { pub unsafe fn bar_1(x: *mut u32) { (*x) = (*x).wrapping_add(1_u32); } +#[repr(C)] +#[derive(Copy, Clone, VaArg, FnPtrArg)] +pub struct Point { + pub x: i32, + pub y: i32, +} +impl Point { + pub unsafe fn new_1() -> Self { + let mut this = Self { x: 0, y: 0 }; + this + } + pub unsafe fn new_2(mut x: i32, mut y: i32) -> Self { + let mut this = Self { x: x, y: y }; + this + } +} +impl Default for Point { + fn default() -> Self { + unsafe { Point::new_1() } + } +} pub fn main() { unsafe { __cpp2rust_init_globals(); @@ -163,6 +184,96 @@ unsafe fn main_0() -> i32 { assert!((((*pair).1 as i32) == (((*pair).0) % (2)))); last = (*pair).0; } + let mut m3: UnsafeMap = UnsafeMap::new(); + let mut inserted: (UnsafeBidirectionalIterator<(i32, i32)>, bool) = { + let __init = (1, 2); + let __inserted = m3.get(&__init.0).is_none(); + if __inserted { + *m3.subscript(&__init.0) = __init.1; + } + (m3.find(&__init.0), __inserted) + }; + assert!((inserted.1 as bool)); + assert!((((*inserted.0.iter_deref()).1) == (2))); + let mut not_inserted: (UnsafeBidirectionalIterator<(i32, i32)>, bool) = { + let __init = (1, 3); + let __inserted = m3.get(&__init.0).is_none(); + if __inserted { + *m3.subscript(&__init.0) = __init.1; + } + (m3.find(&__init.0), __inserted) + }; + assert!(!(not_inserted.1)); + assert!((((*not_inserted.0.iter_deref()).1) == (2))); + { + let __init = { + let mut __a0 = (4, 5); + ((*&mut __a0.0), (*&mut __a0.1)) + }; + let __inserted = m3.get(&__init.0).is_none(); + if __inserted { + *m3.subscript(&__init.0) = __init.1; + } + (m3.find(&__init.0), __inserted) + }; + assert!(((m3.len()) == (2_usize))); + assert!(((*m3.subscript_move(&mut 1, |__k| cpp_move_unsafe!(__k))) == (2))); + assert!(((*m3.subscript_move(&mut 4, |__k| cpp_move_unsafe!(__k))) == (5))); + let mut hinted: UnsafeBidirectionalIterator<(i32, i32)> = { + let _ = >::from(m3.end()); + let __init = (6, 7); + if m3.get(&__init.0).is_none() { + *m3.subscript(&__init.0) = __init.1; + } + m3.find(&__init.0) + }; + assert!((((*hinted.iter_deref()).1) == (7))); + let mut key1: i32 = 1; + let mut tried: (UnsafeBidirectionalIterator<(i32, i32)>, bool) = { + let __key = key1; + let __inserted = m3.get(&__key).is_none(); + if __inserted { + *m3.subscript(&__key) = 9; + } + (m3.find(&__key), __inserted) + }; + assert!(!(tried.1)); + assert!((((*tried.0.iter_deref()).1) == (2))); + let mut key8: i32 = 8; + let mut tried_new: (UnsafeBidirectionalIterator<(i32, i32)>, bool) = { + let __key = key8; + let __inserted = m3.get(&__key).is_none(); + if __inserted { + *m3.subscript(&__key) = 9; + } + (m3.find(&__key), __inserted) + }; + assert!((tried_new.1 as bool)); + assert!(((*m3.subscript_move(&mut 8, |__k| cpp_move_unsafe!(__k))) == (9))); + assert!(((m3.len()) == (4_usize))); + let mut points: UnsafeMap = UnsafeMap::new(); + let mut point_new: (UnsafeBidirectionalIterator<(i32, Point)>, bool) = { + let __key = key1; + let __inserted = points.get(&__key).is_none(); + if __inserted { + *points.subscript(&__key) = Point::new_2({ 3 }, { 4 }); + } + (points.find(&__key), __inserted) + }; + assert!((point_new.1 as bool)); + assert!((((*points.subscript_move(&mut 1, |__k| cpp_move_unsafe!(__k))).x) == (3))); + assert!((((*points.subscript_move(&mut 1, |__k| cpp_move_unsafe!(__k))).y) == (4))); + { + let __init = (key8, Point::new_2({ 5 }, { 6 })); + let __inserted = points.get(&__init.0).is_none(); + if __inserted { + *points.subscript(&__init.0) = __init.1; + } + (points.find(&__init.0), __inserted) + }; + assert!((((*points.subscript_move(&mut 8, |__k| cpp_move_unsafe!(__k))).x) == (5))); + assert!((((*points.subscript_move(&mut 8, |__k| cpp_move_unsafe!(__k))).y) == (6))); + assert!(((points.len()) == (2_usize))); k = 0; let value_0: *const u32 = &raw const (*m.get(&(k as i16)).expect("out of range!")).1; assert!(