Skip to content

Commit a908bf0

Browse files
authored
Spell make_unique for array as the standard does (#574)
```diff - 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); } ``` There is no `std::make_unique<T1[]>(n)` in the standard, only `std::make_unique<T1>(a0)`. Spell the rules as the standard does. --- For that, I added a new marker trait called CppArray that unwraps the element so that the rule for array make_unique can be written as: ``` unsafe fn f1<T1: CppArray<T2>, T2: Default>(a0: usize) -> Option<Box<[T2]>> { Some((0..a0).map(|_| <T2>::default()).collect::<Box<[_]>>()) } ``` CppArray uses the same infrastructure as CppFrom and CppIterator. --- I also had to add a fallback for matching the template arguments. In the new spelling of make_unique, T1 becomes undeducible because it does not appear in the arguments or returns type of the rule. So we deduce T1 from the callee of the return expr.
1 parent ce0915c commit a908bf0

8 files changed

Lines changed: 106 additions & 16 deletions

File tree

‎cpp2rust/converter/rules/decls.cpp‎

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,25 @@ const clang::Expr *GetMacroMemberBase(const clang::SourceManager &sm,
8080
}
8181
}
8282

83+
namespace {
84+
85+
std::vector<clang::TemplateArgument> deducedArguments(
86+
clang::Sema &sema, clang::TemplateParameterList *params,
87+
llvm::SmallVectorImpl<clang::DeducedTemplateArgument> &deduced) {
88+
for (unsigned i = 0; i < deduced.size(); ++i) {
89+
auto nttp =
90+
llvm::dyn_cast<clang::NonTypeTemplateParmDecl>(params->getParam(i));
91+
if (nttp && !nttp->getType()->isDependentType() &&
92+
deduced[i].getKind() == clang::TemplateArgument::Integral) {
93+
deduced[i] = clang::TemplateArgument(
94+
sema.Context, deduced[i].getAsIntegral(), nttp->getType());
95+
}
96+
}
97+
return std::vector<clang::TemplateArgument>(deduced.begin(), deduced.end());
98+
}
99+
100+
} // namespace
101+
83102
std::optional<std::vector<clang::TemplateArgument>>
84103
DeduceFromType(clang::Sema &sema, clang::TemplateParameterList *params,
85104
clang::QualType pattern, clang::QualType actual) {
@@ -94,16 +113,27 @@ DeduceFromType(clang::Sema &sema, clang::TemplateParameterList *params,
94113
trial.failed()) {
95114
return std::nullopt;
96115
}
97-
for (unsigned i = 0; i < deduced.size(); ++i) {
98-
auto nttp =
99-
llvm::dyn_cast<clang::NonTypeTemplateParmDecl>(params->getParam(i));
100-
if (nttp && !nttp->getType()->isDependentType() &&
101-
deduced[i].getKind() == clang::TemplateArgument::Integral) {
102-
deduced[i] = clang::TemplateArgument(
103-
sema.Context, deduced[i].getAsIntegral(), nttp->getType());
104-
}
116+
return deducedArguments(sema, params, deduced);
117+
}
118+
119+
std::optional<std::vector<clang::TemplateArgument>>
120+
DeduceFromArguments(clang::Sema &sema, clang::TemplateParameterList *params,
121+
llvm::ArrayRef<clang::TemplateArgumentLoc> pattern,
122+
llvm::ArrayRef<clang::TemplateArgument> actual) {
123+
Trial trial(sema);
124+
llvm::SmallVector<clang::TemplateArgument, 4> written;
125+
for (const auto &arg : pattern) {
126+
written.push_back(arg.getArgument());
105127
}
106-
return std::vector<clang::TemplateArgument>(deduced.begin(), deduced.end());
128+
llvm::SmallVector<clang::DeducedTemplateArgument, 4> deduced(params->size());
129+
clang::sema::TemplateDeductionInfo info(params->getTemplateLoc());
130+
if (sema.DeduceTemplateArguments(params, written, actual, info, deduced,
131+
/*NumberOfArgumentsMustMatch=*/false) !=
132+
clang::TemplateDeductionResult::Success ||
133+
trial.failed()) {
134+
return std::nullopt;
135+
}
136+
return deducedArguments(sema, params, deduced);
107137
}
108138

109139
namespace {

‎cpp2rust/converter/rules/decls.h‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ std::optional<std::vector<clang::TemplateArgument>>
4646
DeduceFromType(clang::Sema &sema, clang::TemplateParameterList *params,
4747
clang::QualType pattern, clang::QualType actual);
4848

49+
std::optional<std::vector<clang::TemplateArgument>>
50+
DeduceFromArguments(clang::Sema &sema, clang::TemplateParameterList *params,
51+
llvm::ArrayRef<clang::TemplateArgumentLoc> pattern,
52+
llvm::ArrayRef<clang::TemplateArgument> actual);
53+
4954
std::optional<std::vector<clang::TemplateArgument>>
5055
DeduceMemberType(clang::Sema &sema, const clang::TemplateDecl *rule,
5156
clang::QualType pattern, clang::QualType use);

‎cpp2rust/converter/rules/expr_matcher.cpp‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,44 @@ void deduceMemberTypesFromOperands(
272272
}
273273
}
274274

275+
std::optional<std::vector<clang::TemplateArgument>>
276+
deduceFromCallee(clang::Sema &sema, clang::FunctionTemplateDecl *rule,
277+
const clang::Expr *use) {
278+
auto returned = RuleDecls::GetReturned(rule->getTemplatedDecl());
279+
if (!returned) {
280+
return std::nullopt;
281+
}
282+
returned = RuleDecls::SkipImplicit(returned);
283+
if (auto call = llvm::dyn_cast<clang::CallExpr>(returned)) {
284+
returned = call->getCallee()->IgnoreParenImpCasts();
285+
}
286+
llvm::ArrayRef<clang::TemplateArgumentLoc> written;
287+
if (auto overload = llvm::dyn_cast<clang::OverloadExpr>(returned);
288+
overload && overload->hasExplicitTemplateArgs()) {
289+
written = overload->template_arguments();
290+
} else if (auto ref =
291+
llvm::dyn_cast<clang::DependentScopeDeclRefExpr>(returned);
292+
ref && ref->hasExplicitTemplateArgs()) {
293+
written = ref->template_arguments();
294+
} else {
295+
return std::nullopt;
296+
}
297+
use = RuleDecls::SkipImplicit(use);
298+
const clang::Decl *used = nullptr;
299+
if (auto call = llvm::dyn_cast<clang::CallExpr>(use)) {
300+
used = call->getDirectCallee();
301+
} else if (auto ref = llvm::dyn_cast<clang::DeclRefExpr>(use)) {
302+
used = ref->getDecl();
303+
}
304+
auto specialization = llvm::dyn_cast_or_null<clang::FunctionDecl>(used);
305+
if (!specialization || !specialization->getTemplateSpecializationArgs()) {
306+
return std::nullopt;
307+
}
308+
return RuleDecls::DeduceFromArguments(
309+
sema, rule->getTemplateParameters(), written,
310+
specialization->getTemplateSpecializationArgs()->asArray());
311+
}
312+
275313
clang::TemplateArgumentListInfo getResultArgs(clang::Sema &sema,
276314
clang::FunctionTemplateDecl *rule,
277315
const clang::Expr *use) {
@@ -294,6 +332,13 @@ clang::TemplateArgumentListInfo getResultArgs(clang::Sema &sema,
294332
.getCanonicalType()
295333
.getUnqualifiedType())
296334
.value_or(std::vector<clang::TemplateArgument>(params->size()));
335+
if (auto from_callee = deduceFromCallee(sema, rule, use)) {
336+
for (unsigned i = 0; i < deduced.size(); ++i) {
337+
if (deduced[i].isNull()) {
338+
deduced[i] = (*from_callee)[i];
339+
}
340+
}
341+
}
297342
deduceMemberTypesFromOperands(sema, rule, use, deduced);
298343
auto last = static_cast<unsigned>(deducible.find_last_unset());
299344
for (unsigned i = 0; i < params->size() && i <= last; ++i) {

‎cpp2rust/converter/rules/registry.cpp‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,8 @@ unsigned iteratorOverGeneric(const TranslationRule::ExprRule &rule,
133133
unsigned n) {
134134
for (unsigned i = 0; i < rule.generics.size(); ++i) {
135135
for (const auto &bound : rule.generics[i]) {
136-
if (llvm::StringRef(bound.trait_name).ends_with("Iterator") &&
136+
llvm::StringRef trait = bound.trait_name;
137+
if ((trait.ends_with("Iterator") || trait == "CppArray") &&
137138
llvm::is_contained(bound.args, n)) {
138139
return i + 1;
139140
}
@@ -413,6 +414,9 @@ clang::QualType iteratorElementType(clang::ASTContext &ctx,
413414
if (iterator->isPointerType()) {
414415
return iterator->getPointeeType().getUnqualifiedType();
415416
}
417+
if (auto *array = ctx.getAsArrayType(iterator)) {
418+
return array->getElementType().getUnqualifiedType();
419+
}
416420
auto [rule, bindings] = Search(ctx, iterator);
417421
assert(rule && !bindings.empty() &&
418422
bindings[0].getKind() == clang::TemplateArgument::Type &&

‎rules/unique_ptr/shim.rs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Copyright (c) 2022-present INESC-ID.
2+
// Distributed under the MIT license that can be found in the LICENSE file.
3+
4+
pub trait CppArray<T> {}

‎rules/unique_ptr/src_cxx14.cpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77

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

10-
template <typename T1> std::unique_ptr<T1[]> f1(std::size_t n) {
11-
return std::make_unique<T1[]>(n);
10+
template <typename T1> auto f1(std::size_t a0) {
11+
return std::make_unique<T1>(a0);
1212
}
1313

1414
template <typename T1, typename... Args>

‎rules/unique_ptr/tgt_refcount.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ fn t4<T1>() -> Ptr<T1> {
2121
Ptr::null()
2222
}
2323

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

‎rules/unique_ptr/tgt_unsafe.rs‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright (c) 2022-present INESC-ID.
22
// Distributed under the MIT license that can be found in the LICENSE file.
33

4+
use libcc2rs::*;
5+
46
fn t1<T1>() -> Option<Box<T1>> {
57
None
68
}
@@ -17,8 +19,8 @@ fn t4<T1>() -> *mut T1 {
1719
::std::ptr::null_mut()
1820
}
1921

20-
unsafe fn f1<T1: Default>(a0: usize) -> Option<Box<[T1]>> {
21-
Some((0..a0).map(|_| <T1>::default()).collect::<Box<[_]>>())
22+
unsafe fn f1<T1: CppArray<T2>, T2: Default>(a0: usize) -> Option<Box<[T2]>> {
23+
Some((0..a0).map(|_| <T2>::default()).collect::<Box<[_]>>())
2224
}
2325
unsafe fn f2<T1>(a0: &mut Option<Box<T1>>) -> *mut T1 {
2426
a0.as_deref_mut()

0 commit comments

Comments
 (0)