diff --git a/cpp2rust/converter/rules/decls.cpp b/cpp2rust/converter/rules/decls.cpp index 0622645711..eef1cf697f 100644 --- a/cpp2rust/converter/rules/decls.cpp +++ b/cpp2rust/converter/rules/decls.cpp @@ -80,6 +80,25 @@ const clang::Expr *GetMacroMemberBase(const clang::SourceManager &sm, } } +namespace { + +std::vector deducedArguments( + clang::Sema &sema, clang::TemplateParameterList *params, + llvm::SmallVectorImpl &deduced) { + for (unsigned i = 0; i < deduced.size(); ++i) { + auto nttp = + llvm::dyn_cast(params->getParam(i)); + if (nttp && !nttp->getType()->isDependentType() && + deduced[i].getKind() == clang::TemplateArgument::Integral) { + deduced[i] = clang::TemplateArgument( + sema.Context, deduced[i].getAsIntegral(), nttp->getType()); + } + } + return std::vector(deduced.begin(), deduced.end()); +} + +} // namespace + std::optional> DeduceFromType(clang::Sema &sema, clang::TemplateParameterList *params, clang::QualType pattern, clang::QualType actual) { @@ -94,16 +113,27 @@ DeduceFromType(clang::Sema &sema, clang::TemplateParameterList *params, trial.failed()) { return std::nullopt; } - for (unsigned i = 0; i < deduced.size(); ++i) { - auto nttp = - llvm::dyn_cast(params->getParam(i)); - if (nttp && !nttp->getType()->isDependentType() && - deduced[i].getKind() == clang::TemplateArgument::Integral) { - deduced[i] = clang::TemplateArgument( - sema.Context, deduced[i].getAsIntegral(), nttp->getType()); - } + return deducedArguments(sema, params, deduced); +} + +std::optional> +DeduceFromArguments(clang::Sema &sema, clang::TemplateParameterList *params, + llvm::ArrayRef pattern, + llvm::ArrayRef actual) { + Trial trial(sema); + llvm::SmallVector written; + for (const auto &arg : pattern) { + written.push_back(arg.getArgument()); } - return std::vector(deduced.begin(), deduced.end()); + llvm::SmallVector deduced(params->size()); + clang::sema::TemplateDeductionInfo info(params->getTemplateLoc()); + if (sema.DeduceTemplateArguments(params, written, actual, info, deduced, + /*NumberOfArgumentsMustMatch=*/false) != + clang::TemplateDeductionResult::Success || + trial.failed()) { + return std::nullopt; + } + return deducedArguments(sema, params, deduced); } namespace { diff --git a/cpp2rust/converter/rules/decls.h b/cpp2rust/converter/rules/decls.h index 018aa069ff..3c62975a7e 100644 --- a/cpp2rust/converter/rules/decls.h +++ b/cpp2rust/converter/rules/decls.h @@ -46,6 +46,11 @@ std::optional> DeduceFromType(clang::Sema &sema, clang::TemplateParameterList *params, clang::QualType pattern, clang::QualType actual); +std::optional> +DeduceFromArguments(clang::Sema &sema, clang::TemplateParameterList *params, + llvm::ArrayRef pattern, + llvm::ArrayRef actual); + std::optional> DeduceMemberType(clang::Sema &sema, const clang::TemplateDecl *rule, clang::QualType pattern, clang::QualType use); diff --git a/cpp2rust/converter/rules/expr_matcher.cpp b/cpp2rust/converter/rules/expr_matcher.cpp index e37369771e..2fcfcb7aca 100644 --- a/cpp2rust/converter/rules/expr_matcher.cpp +++ b/cpp2rust/converter/rules/expr_matcher.cpp @@ -272,6 +272,44 @@ void deduceMemberTypesFromOperands( } } +std::optional> +deduceFromCallee(clang::Sema &sema, clang::FunctionTemplateDecl *rule, + const clang::Expr *use) { + auto returned = RuleDecls::GetReturned(rule->getTemplatedDecl()); + if (!returned) { + return std::nullopt; + } + returned = RuleDecls::SkipImplicit(returned); + if (auto call = llvm::dyn_cast(returned)) { + returned = call->getCallee()->IgnoreParenImpCasts(); + } + llvm::ArrayRef written; + if (auto overload = llvm::dyn_cast(returned); + overload && overload->hasExplicitTemplateArgs()) { + written = overload->template_arguments(); + } else if (auto ref = + llvm::dyn_cast(returned); + ref && ref->hasExplicitTemplateArgs()) { + written = ref->template_arguments(); + } else { + return std::nullopt; + } + use = RuleDecls::SkipImplicit(use); + const clang::Decl *used = nullptr; + if (auto call = llvm::dyn_cast(use)) { + used = call->getDirectCallee(); + } else if (auto ref = llvm::dyn_cast(use)) { + used = ref->getDecl(); + } + auto specialization = llvm::dyn_cast_or_null(used); + if (!specialization || !specialization->getTemplateSpecializationArgs()) { + return std::nullopt; + } + return RuleDecls::DeduceFromArguments( + sema, rule->getTemplateParameters(), written, + specialization->getTemplateSpecializationArgs()->asArray()); +} + clang::TemplateArgumentListInfo getResultArgs(clang::Sema &sema, clang::FunctionTemplateDecl *rule, const clang::Expr *use) { @@ -294,6 +332,13 @@ clang::TemplateArgumentListInfo getResultArgs(clang::Sema &sema, .getCanonicalType() .getUnqualifiedType()) .value_or(std::vector(params->size())); + if (auto from_callee = deduceFromCallee(sema, rule, use)) { + for (unsigned i = 0; i < deduced.size(); ++i) { + if (deduced[i].isNull()) { + deduced[i] = (*from_callee)[i]; + } + } + } deduceMemberTypesFromOperands(sema, rule, use, deduced); auto last = static_cast(deducible.find_last_unset()); for (unsigned i = 0; i < params->size() && i <= last; ++i) { diff --git a/cpp2rust/converter/rules/registry.cpp b/cpp2rust/converter/rules/registry.cpp index 5b98e5e03e..974925fe40 100644 --- a/cpp2rust/converter/rules/registry.cpp +++ b/cpp2rust/converter/rules/registry.cpp @@ -133,7 +133,8 @@ unsigned iteratorOverGeneric(const TranslationRule::ExprRule &rule, unsigned n) { for (unsigned i = 0; i < rule.generics.size(); ++i) { for (const auto &bound : rule.generics[i]) { - if (llvm::StringRef(bound.trait_name).ends_with("Iterator") && + llvm::StringRef trait = bound.trait_name; + if ((trait.ends_with("Iterator") || trait == "CppArray") && llvm::is_contained(bound.args, n)) { return i + 1; } @@ -413,6 +414,9 @@ clang::QualType iteratorElementType(clang::ASTContext &ctx, if (iterator->isPointerType()) { return iterator->getPointeeType().getUnqualifiedType(); } + if (auto *array = ctx.getAsArrayType(iterator)) { + return array->getElementType().getUnqualifiedType(); + } auto [rule, bindings] = Search(ctx, iterator); assert(rule && !bindings.empty() && bindings[0].getKind() == clang::TemplateArgument::Type && diff --git a/rules/unique_ptr/shim.rs b/rules/unique_ptr/shim.rs new file mode 100644 index 0000000000..67808c7161 --- /dev/null +++ b/rules/unique_ptr/shim.rs @@ -0,0 +1,4 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +pub trait CppArray {} diff --git a/rules/unique_ptr/src_cxx14.cpp b/rules/unique_ptr/src_cxx14.cpp index cf18c0b2d1..e8a5d76b1b 100644 --- a/rules/unique_ptr/src_cxx14.cpp +++ b/rules/unique_ptr/src_cxx14.cpp @@ -7,8 +7,8 @@ #include "../common/init.h" -template std::unique_ptr f1(std::size_t n) { - return std::make_unique(n); +template auto f1(std::size_t a0) { + return std::make_unique(a0); } template diff --git a/rules/unique_ptr/tgt_refcount.rs b/rules/unique_ptr/tgt_refcount.rs index 20591c6a0a..00691fd026 100644 --- a/rules/unique_ptr/tgt_refcount.rs +++ b/rules/unique_ptr/tgt_refcount.rs @@ -21,9 +21,9 @@ fn t4() -> Ptr { Ptr::null() } -fn f1(a0: usize) -> Option>> { +fn f1, T2: Default>(a0: usize) -> Option>> { Some(Rc::new(RefCell::new( - (0..a0).map(|_| ::default()).collect::>(), + (0..a0).map(|_| ::default()).collect::>(), ))) } diff --git a/rules/unique_ptr/tgt_unsafe.rs b/rules/unique_ptr/tgt_unsafe.rs index c296402902..dc6d0e68cd 100644 --- a/rules/unique_ptr/tgt_unsafe.rs +++ b/rules/unique_ptr/tgt_unsafe.rs @@ -1,6 +1,8 @@ // 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 } @@ -17,8 +19,8 @@ fn t4() -> *mut T1 { ::std::ptr::null_mut() } -unsafe fn f1(a0: usize) -> Option> { - Some((0..a0).map(|_| ::default()).collect::>()) +unsafe fn f1, T2: Default>(a0: usize) -> Option> { + Some((0..a0).map(|_| ::default()).collect::>()) } unsafe fn f2(a0: &mut Option>) -> *mut T1 { a0.as_deref_mut()