Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 39 additions & 9 deletions cpp2rust/converter/rules/decls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,25 @@ const clang::Expr *GetMacroMemberBase(const clang::SourceManager &sm,
}
}

namespace {

std::vector<clang::TemplateArgument> deducedArguments(
clang::Sema &sema, clang::TemplateParameterList *params,
llvm::SmallVectorImpl<clang::DeducedTemplateArgument> &deduced) {
for (unsigned i = 0; i < deduced.size(); ++i) {
auto nttp =
llvm::dyn_cast<clang::NonTypeTemplateParmDecl>(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<clang::TemplateArgument>(deduced.begin(), deduced.end());
}

} // namespace

std::optional<std::vector<clang::TemplateArgument>>
DeduceFromType(clang::Sema &sema, clang::TemplateParameterList *params,
clang::QualType pattern, clang::QualType actual) {
Expand All @@ -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<clang::NonTypeTemplateParmDecl>(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<std::vector<clang::TemplateArgument>>
DeduceFromArguments(clang::Sema &sema, clang::TemplateParameterList *params,
llvm::ArrayRef<clang::TemplateArgumentLoc> pattern,
llvm::ArrayRef<clang::TemplateArgument> actual) {
Trial trial(sema);
llvm::SmallVector<clang::TemplateArgument, 4> written;
for (const auto &arg : pattern) {
written.push_back(arg.getArgument());
}
return std::vector<clang::TemplateArgument>(deduced.begin(), deduced.end());
llvm::SmallVector<clang::DeducedTemplateArgument, 4> 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 {
Expand Down
5 changes: 5 additions & 0 deletions cpp2rust/converter/rules/decls.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ std::optional<std::vector<clang::TemplateArgument>>
DeduceFromType(clang::Sema &sema, clang::TemplateParameterList *params,
clang::QualType pattern, clang::QualType actual);

std::optional<std::vector<clang::TemplateArgument>>
DeduceFromArguments(clang::Sema &sema, clang::TemplateParameterList *params,
llvm::ArrayRef<clang::TemplateArgumentLoc> pattern,
llvm::ArrayRef<clang::TemplateArgument> actual);

std::optional<std::vector<clang::TemplateArgument>>
DeduceMemberType(clang::Sema &sema, const clang::TemplateDecl *rule,
clang::QualType pattern, clang::QualType use);
Expand Down
45 changes: 45 additions & 0 deletions cpp2rust/converter/rules/expr_matcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,44 @@ void deduceMemberTypesFromOperands(
}
}

std::optional<std::vector<clang::TemplateArgument>>
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<clang::CallExpr>(returned)) {
returned = call->getCallee()->IgnoreParenImpCasts();
}
llvm::ArrayRef<clang::TemplateArgumentLoc> written;
if (auto overload = llvm::dyn_cast<clang::OverloadExpr>(returned);
overload && overload->hasExplicitTemplateArgs()) {
written = overload->template_arguments();
} else if (auto ref =
llvm::dyn_cast<clang::DependentScopeDeclRefExpr>(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<clang::CallExpr>(use)) {
used = call->getDirectCallee();
} else if (auto ref = llvm::dyn_cast<clang::DeclRefExpr>(use)) {
used = ref->getDecl();
}
auto specialization = llvm::dyn_cast_or_null<clang::FunctionDecl>(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) {
Expand All @@ -294,6 +332,13 @@ clang::TemplateArgumentListInfo getResultArgs(clang::Sema &sema,
.getCanonicalType()
.getUnqualifiedType())
.value_or(std::vector<clang::TemplateArgument>(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<unsigned>(deducible.find_last_unset());
for (unsigned i = 0; i < params->size() && i <= last; ++i) {
Expand Down
6 changes: 5 additions & 1 deletion cpp2rust/converter/rules/registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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 &&
Expand Down
4 changes: 4 additions & 0 deletions rules/unique_ptr/shim.rs
Original file line number Diff line number Diff line change
@@ -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<T> {}
4 changes: 2 additions & 2 deletions rules/unique_ptr/src_cxx14.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

#include "../common/init.h"

template <typename T1> std::unique_ptr<T1[]> f1(std::size_t n) {
return std::make_unique<T1[]>(n);
template <typename T1> auto f1(std::size_t a0) {
return std::make_unique<T1>(a0);
}

template <typename T1, typename... Args>
Expand Down
4 changes: 2 additions & 2 deletions rules/unique_ptr/tgt_refcount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ fn t4<T1>() -> Ptr<T1> {
Ptr::null()
}

fn f1<T1: Default>(a0: usize) -> Option<Value<Box<[T1]>>> {
fn f1<T1: CppArray<T2>, T2: Default>(a0: usize) -> Option<Value<Box<[T2]>>> {
Some(Rc::new(RefCell::new(
(0..a0).map(|_| <T1>::default()).collect::<Box<[_]>>(),
(0..a0).map(|_| <T2>::default()).collect::<Box<[_]>>(),
)))
}

Expand Down
6 changes: 4 additions & 2 deletions rules/unique_ptr/tgt_unsafe.rs
Original file line number Diff line number Diff line change
@@ -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<T1>() -> Option<Box<T1>> {
None
}
Expand All @@ -17,8 +19,8 @@ fn t4<T1>() -> *mut T1 {
::std::ptr::null_mut()
}

unsafe fn f1<T1: Default>(a0: usize) -> Option<Box<[T1]>> {
Some((0..a0).map(|_| <T1>::default()).collect::<Box<[_]>>())
unsafe fn f1<T1: CppArray<T2>, T2: Default>(a0: usize) -> Option<Box<[T2]>> {
Some((0..a0).map(|_| <T2>::default()).collect::<Box<[_]>>())
}
unsafe fn f2<T1>(a0: &mut Option<Box<T1>>) -> *mut T1 {
a0.as_deref_mut()
Expand Down
Loading