Skip to content

Commit 937c2cc

Browse files
authored
Move std::array and std::initializer_list în rules (#545)
1 parent 0a50394 commit 937c2cc

49 files changed

Lines changed: 187 additions & 122 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎cpp2rust/converter/converter.cpp‎

Lines changed: 14 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -723,9 +723,8 @@ bool Converter::TypeDerivesDefault(clang::QualType qual_type) {
723723
return false;
724724
}
725725

726-
// Types that need a custom array initializer (e.g., std::array, which is
727-
// translated to Vec)
728-
if (!GetArrayDefaultAsString(qual_type).empty()) {
726+
auto *cxx_record = qual_type->getAsCXXRecordDecl();
727+
if (IsStdDecl(cxx_record, "array") || IsStdDecl(cxx_record, "basic_string")) {
729728
return false;
730729
}
731730

@@ -3613,22 +3612,20 @@ bool Converter::VisitInitListExpr(clang::InitListExpr *expr) {
36133612
}
36143613
} else if (qual_type->isRecordType()) {
36153614
const auto *record = qual_type->getAsRecordDecl();
3616-
if (record->getQualifiedNameAsString() == "std::array") {
3617-
if (auto init = clang::dyn_cast<clang::InitListExpr>(expr->getInit(0))) {
3618-
StrCat("vec!");
3619-
VisitInitListExpr(init);
3620-
} else {
3621-
StrCat(GetArrayDefaultAsString(qual_type));
3622-
}
3615+
if (syntactic->getNumInits() == 0) {
3616+
StrCat(GetDefaultAsString(qual_type));
36233617
SetFreshType(qual_type);
36243618
return false;
36253619
}
36263620

3627-
if (syntactic->getNumInits() == 0) {
3628-
StrCat(GetDefaultAsString(qual_type));
3621+
if (auto str =
3622+
GetMappedAsString(expr, expr->getInits(), expr->getNumInits());
3623+
!str.empty()) {
3624+
StrCat(str);
36293625
SetFreshType(qual_type);
36303626
return false;
36313627
}
3628+
assert(IsUserDefinedDecl(record) && "aggregate list without a rule");
36323629

36333630
StrCat(GetUnsafeTypeAsString(qual_type));
36343631
PushBrace brace(*this);
@@ -4258,11 +4255,11 @@ bool Converter::VisitClassTemplateDecl(clang::ClassTemplateDecl *decl) {
42584255

42594256
bool Converter::VisitCXXStdInitializerListExpr(
42604257
clang::CXXStdInitializerListExpr *expr) {
4261-
if (expr->getSubExpr()->getType()->isArrayType()) {
4262-
// Arrays become Vec's
4263-
StrCat("vec!");
4264-
}
4265-
Convert(expr->getSubExpr());
4258+
auto *backing = expr->getSubExpr();
4259+
auto str = GetMappedAsString(expr, &backing, 1);
4260+
ENSURE(!str.empty());
4261+
StrCat(str);
4262+
SetFreshType(expr->getType());
42664263
return false;
42674264
}
42684265

@@ -4283,33 +4280,6 @@ std::string Converter::GetArrayDefaultAsString(clang::QualType qual_type) {
42834280
if (clang::isa<clang::IncompleteArrayType>(qual_type)) {
42844281
return "[]";
42854282
}
4286-
if (IsStdDecl(qual_type->getAsCXXRecordDecl(), "array")) {
4287-
assert(GetTemplateArgs(qual_type).has_value());
4288-
auto template_args = *GetTemplateArgs(qual_type);
4289-
assert(template_args.size() == 2);
4290-
auto array_size = template_args[1];
4291-
unsigned size = 0;
4292-
switch (array_size.getKind()) {
4293-
case clang::TemplateArgument::Expression: {
4294-
auto array_size_expr = array_size.getAsExpr();
4295-
assert(array_size_expr && !array_size_expr->isValueDependent());
4296-
clang::Expr::EvalResult result;
4297-
ENSURE(array_size_expr->EvaluateAsInt(result, ctx_));
4298-
size = result.Val.getInt().getZExtValue();
4299-
break;
4300-
}
4301-
case clang::TemplateArgument::Integral: {
4302-
size = array_size.getAsIntegral().getZExtValue();
4303-
break;
4304-
}
4305-
default:
4306-
assert(0 && "Unsupported array size kind");
4307-
break;
4308-
}
4309-
return std::format(
4310-
"std::array::from_fn::<_, {}, _>(|_| Default::default()).to_vec()",
4311-
size);
4312-
}
43134283
return {};
43144284
}
43154285

‎cpp2rust/converter/models/converter_refcount.cpp‎

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1882,18 +1882,6 @@ bool ConverterRefCount::VisitInitListExpr(clang::InitListExpr *expr) {
18821882

18831883
if (qual_type->isRecordType()) {
18841884
const auto *record = qual_type->getAsRecordDecl();
1885-
if (record->getQualifiedNameAsString() == "std::array") {
1886-
if (auto init = clang::dyn_cast<clang::InitListExpr>(expr->getInit(0))) {
1887-
StrCat("vec!");
1888-
PushConversionKind push(*this, ConversionKind::Unboxed);
1889-
ConverterRefCount::VisitInitListExpr(init);
1890-
} else {
1891-
StrCat(GetArrayDefaultAsString(qual_type));
1892-
}
1893-
computed_expr_type_ = ComputedExprType::FreshValue;
1894-
return false;
1895-
}
1896-
18971885
if (syntactic->getNumInits() == 0) {
18981886
{
18991887
PushConversionKind push(*this, ConversionKind::Unboxed);
@@ -1903,6 +1891,18 @@ bool ConverterRefCount::VisitInitListExpr(clang::InitListExpr *expr) {
19031891
return false;
19041892
}
19051893

1894+
{
1895+
PushConversionKind push(*this, ConversionKind::Unboxed);
1896+
if (auto str =
1897+
GetMappedAsString(expr, expr->getInits(), expr->getNumInits());
1898+
!str.empty()) {
1899+
StrCat(str);
1900+
computed_expr_type_ = ComputedExprType::FreshValue;
1901+
return false;
1902+
}
1903+
}
1904+
assert(IsUserDefinedDecl(record) && "aggregate list without a rule");
1905+
19061906
if (record->isUnion()) {
19071907
auto *field = expr->getInitializedFieldInUnion();
19081908
assert(field && expr->getNumInits() == 1);

‎cpp2rust/converter/rules/decls.cpp‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,15 @@ DeduceFromType(clang::Sema &sema, clang::TemplateParameterList *params,
9191
trial.failed()) {
9292
return std::nullopt;
9393
}
94+
for (unsigned i = 0; i < deduced.size(); ++i) {
95+
auto nttp =
96+
llvm::dyn_cast<clang::NonTypeTemplateParmDecl>(params->getParam(i));
97+
if (nttp && !nttp->getType()->isDependentType() &&
98+
deduced[i].getKind() == clang::TemplateArgument::Integral) {
99+
deduced[i] = clang::TemplateArgument(
100+
sema.Context, deduced[i].getAsIntegral(), nttp->getType());
101+
}
102+
}
94103
return std::vector<clang::TemplateArgument>(deduced.begin(), deduced.end());
95104
}
96105

‎cpp2rust/converter/rules/expr_matcher.cpp‎

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@
1616
#include <llvm/ADT/SmallBitVector.h>
1717

1818
#include <cassert>
19+
#include <compare>
1920
#include <optional>
2021
#include <string>
2122
#include <variant>
2223
#include <vector>
2324

2425
#include "converter/rules/decls.h"
26+
#include "converter/rules/rule_keys.h"
2527

2628
namespace cpp2rust::AstMatcher {
2729

@@ -50,18 +52,25 @@ bool hasSameArgTypes(clang::ASTContext &ctx, const clang::Expr *use,
5052
struct MacroUsage {
5153
std::string name;
5254

53-
bool operator==(const MacroUsage &) const = default;
55+
auto operator<=>(const MacroUsage &) const = default;
5456
};
5557

5658
struct RewrittenOperatorUsage {
5759
const clang::Decl *decl;
5860
clang::BinaryOperatorKind op;
5961

60-
bool operator==(const RewrittenOperatorUsage &) const = default;
62+
auto operator<=>(const RewrittenOperatorUsage &) const = default;
6163
};
6264

63-
using ResolvedDecl = std::variant<std::monostate, const clang::Decl *,
64-
MacroUsage, RewrittenOperatorUsage>;
65+
struct AggregateUsage {
66+
RuleKeys::TypeKey type;
67+
68+
auto operator<=>(const AggregateUsage &) const = default;
69+
};
70+
71+
using ResolvedDecl =
72+
std::variant<std::monostate, const clang::Decl *, MacroUsage,
73+
RewrittenOperatorUsage, AggregateUsage>;
6574

6675
ResolvedDecl getResolvedDecl(clang::ASTContext &ctx, const clang::Expr *expr,
6776
bool must_resolve) {
@@ -85,6 +94,17 @@ ResolvedDecl getResolvedDecl(clang::ASTContext &ctx, const clang::Expr *expr,
8594
if (auto cast = llvm::dyn_cast<clang::ExplicitCastExpr>(expr)) {
8695
return getResolvedDecl(ctx, cast->getSubExpr(), must_resolve);
8796
}
97+
if (auto list = llvm::dyn_cast<clang::InitListExpr>(expr);
98+
list && list->getType()->isRecordType()) {
99+
return AggregateUsage{*RuleKeys::GetTypeKey(list->getType())};
100+
}
101+
if (llvm::isa<clang::CXXStdInitializerListExpr>(expr)) {
102+
return AggregateUsage{*RuleKeys::GetTypeKey(expr->getType())};
103+
}
104+
if (auto construct = llvm::dyn_cast<clang::CXXUnresolvedConstructExpr>(expr);
105+
construct && construct->isListInitialization()) {
106+
return AggregateUsage{*RuleKeys::GetTypeKey(construct->getTypeAsWritten())};
107+
}
88108
if (auto call = llvm::dyn_cast<clang::CallExpr>(expr)) {
89109
if (auto callee = call->getDirectCallee()) {
90110
return callee->getCanonicalDecl();
@@ -149,6 +169,11 @@ std::vector<clang::Expr *> getOperands(clang::ASTContext &ctx,
149169
operands.insert(operands.end(), call->arg_begin(), call->arg_end());
150170
} else if (auto construct = llvm::dyn_cast<clang::CXXConstructExpr>(expr)) {
151171
operands.assign(construct->arg_begin(), construct->arg_end());
172+
} else if (auto list = llvm::dyn_cast<clang::InitListExpr>(expr)) {
173+
operands.assign(list->inits().begin(), list->inits().end());
174+
} else if (auto list =
175+
llvm::dyn_cast<clang::CXXStdInitializerListExpr>(expr)) {
176+
operands.push_back(list->getSubExpr()->IgnoreImplicit());
152177
} else if (auto member = llvm::dyn_cast<clang::MemberExpr>(expr)) {
153178
auto macro_base =
154179
RuleDecls::GetMacroMemberBase(ctx.getSourceManager(), member);
@@ -233,7 +258,10 @@ clang::TemplateArgumentListInfo getResultArgs(clang::Sema &sema,
233258
clang::TemplateArgumentListInfo explicit_args(loc, loc);
234259
llvm::SmallBitVector deducible;
235260
sema.MarkDeducedTemplateParameters(rule, deducible);
236-
if (deducible.all()) {
261+
bool aggregate =
262+
llvm::isa<clang::InitListExpr, clang::CXXStdInitializerListExpr>(
263+
RuleDecls::SkipImplicit(use));
264+
if (deducible.all() && !aggregate) {
237265
return explicit_args;
238266
}
239267
auto params = rule->getTemplateParameters();
@@ -247,7 +275,7 @@ clang::TemplateArgumentListInfo getResultArgs(clang::Sema &sema,
247275
return explicit_args;
248276
}
249277
auto last = static_cast<unsigned>(deducible.find_last_unset());
250-
for (unsigned i = 0; i <= last; ++i) {
278+
for (unsigned i = 0; i < params->size() && i <= last; ++i) {
251279
auto param = params->getParam(i);
252280
if (param->isParameterPack() || (*deduced)[i].isNull()) {
253281
break;
@@ -320,6 +348,17 @@ MatchResult matchTemplate(clang::Sema &sema, const clang::Expr *use,
320348
auto explicit_args = getResultArgs(sema, rule, use);
321349
auto specialization =
322350
deduce(sema, rule, explicit_args, getOperands(ctx, use));
351+
if (!specialization) {
352+
return std::nullopt;
353+
}
354+
if (std::holds_alternative<AggregateUsage>(usage_decl)) {
355+
auto returned = RuleDecls::GetReturned(rule->getTemplatedDecl());
356+
if (getResolvedDecl(ctx, returned, /*must_resolve=*/false) != usage_decl) {
357+
return std::nullopt;
358+
}
359+
checkCallable(sema, use, rule->getTemplatedDecl());
360+
return specialization->getTemplateSpecializationArgs()->asArray();
361+
}
323362
auto returned =
324363
substituteSpecializationInRuleTmpl(sema, rule, specialization);
325364
if (!returned ||

‎cpp2rust/converter/rules/rule_keys.cpp‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,13 @@ std::optional<ExprKey> getExprKey(clang::ASTContext &ctx,
183183
if (llvm::isa<clang::ArraySubscriptExpr>(expr)) {
184184
return getOperatorKey(ctx, clang::OO_Subscript);
185185
}
186+
if (auto list = llvm::dyn_cast<clang::InitListExpr>(expr);
187+
list && list->getType()->isRecordType()) {
188+
return getConstructorKey(getParent(list->getType()));
189+
}
190+
if (llvm::isa<clang::CXXStdInitializerListExpr>(expr)) {
191+
return getConstructorKey(getParent(expr->getType()));
192+
}
186193
return std::nullopt;
187194
}
188195

‎cpp2rust/converter/rules/rule_keys.h‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <clang/AST/Type.h>
1111
#include <llvm/ADT/Hashing.h>
1212

13+
#include <compare>
1314
#include <optional>
1415
#include <variant>
1516
#include <vector>
@@ -26,7 +27,7 @@ struct Member {
2627
struct Constructor {
2728
const clang::Decl *parent;
2829

29-
bool operator==(const Constructor &) const = default;
30+
auto operator<=>(const Constructor &) const = default;
3031
};
3132

3233
struct Unqualified {

‎cpp2rust/converter/rules/rules_loader.cpp‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,13 @@ std::string ExprKey(clang::ASTContext &ctx, const clang::Expr *expr) {
489489
if (auto construct = llvm::dyn_cast<clang::CXXConstructExpr>(expr)) {
490490
return FunctionKey(construct->getConstructor());
491491
}
492+
if (llvm::isa<clang::InitListExpr, clang::CXXStdInitializerListExpr>(expr)) {
493+
if (auto record = expr->getType()->getAsRecordDecl();
494+
record && !IsUserDefinedDecl(record)) {
495+
return ConstructorKey(ClassKey(record));
496+
}
497+
return {};
498+
}
492499
if (auto member = llvm::dyn_cast<clang::MemberExpr>(expr)) {
493500
if (RuleDecls::GetMacroMemberBase(ctx.getSourceManager(), member)) {
494501
return clang::Lexer::getImmediateMacroName(member->getMemberLoc(),

‎rules/array/src.cpp‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,7 @@ template <typename T1, std::size_t T2>
4141
std::array<T1, T2> &f7(std::array<T1, T2> &dst, const std::array<T1, T2> &src) {
4242
return dst = src;
4343
}
44+
45+
template <typename T1, std::size_t T2> std::array<T1, T2> f8(T1 (&&a0)[T2]) {
46+
return std::array<T1, T2>{a0};
47+
}

‎rules/array/tgt_unsafe.rs‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
use libcc2rs::*;
55

6-
fn t1<T1>() -> Vec<T1> {
7-
Default::default()
6+
fn t1<T1: Default + Clone, const T2: usize>() -> Vec<T1> {
7+
std::array::from_fn::<_, T2, _>(|_| <T1>::default()).to_vec()
88
}
99

1010
fn t2() -> usize {
@@ -38,3 +38,7 @@ unsafe fn f6<T1: Clone>(a0: Vec<T1>) -> Vec<T1> {
3838
unsafe fn f7<T1: Clone>(a0: &mut Vec<T1>, a1: Vec<T1>) {
3939
*a0 = a1.clone()
4040
}
41+
42+
unsafe fn f8<T1, const T2: usize>(a0: [T1; T2]) -> Vec<T1> {
43+
Vec::from(a0)
44+
}

‎rules/initializer_list/src.cpp‎

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

4+
#include <cstddef>
45
#include <initializer_list>
56

67
template <typename T1> using t1 = std::initializer_list<T1>;
@@ -12,3 +13,8 @@ typename std::initializer_list<T1>::size_type
1213
f1(const std::initializer_list<T1> &o) {
1314
return o.size();
1415
}
16+
17+
template <typename T1, std::size_t T2>
18+
std::initializer_list<T1> f2(const T1 (&a0)[T2]) {
19+
return std::initializer_list<T1>{a0};
20+
}

0 commit comments

Comments
 (0)