Skip to content

Commit 6b9ccc3

Browse files
committed
Merge branch 'master' into ast-matcher
2 parents c371a7e + d84269b commit 6b9ccc3

74 files changed

Lines changed: 1874 additions & 270 deletions

File tree

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: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "converter/converter.h"
55

66
#include <clang/AST/APValue.h>
7+
#include <clang/AST/IgnoreExpr.h>
78
#include <clang/AST/ParentMapContext.h>
89
#include <clang/Basic/LangOptions.h>
910
#include <clang/Basic/SourceManager.h>
@@ -303,6 +304,9 @@ Converter::ConvertFunctionPointerType(const clang::FunctionProtoType *proto) {
303304
result += ToString(p_ty);
304305
result += ',';
305306
}
307+
if (proto->isVariadic()) {
308+
result += "Box<[VaArg]>,";
309+
}
306310
result += ')';
307311
if (!proto->getReturnType()->isVoidType()) {
308312
result += std::format(" -> {}", ToString(proto->getReturnType()));
@@ -522,6 +526,9 @@ bool Converter::ConvertVarDeclSkipInit(clang::VarDecl *decl) {
522526
ENSURE(decl_ids_.insert(GetID(decl)).second);
523527
global_inits_.push_back(ForceGlobalInit(decl));
524528
} else if (decl->isStaticLocal()) {
529+
if (!globals_.insert(name).second) {
530+
return false;
531+
}
525532
StrCat(keyword::kStatic, keyword_mut_);
526533
} else if (decl->isLocalVarDecl()) {
527534
StrCat(keyword::kLet);
@@ -2012,6 +2019,16 @@ std::string Converter::GetFunctionRefName(const clang::FunctionDecl *fn_decl) {
20122019

20132020
void Converter::ConvertFunctionToFunctionPointer(
20142021
const clang::FunctionDecl *fn_decl) {
2022+
if (auto *method = clang::dyn_cast<clang::CXXMethodDecl>(fn_decl);
2023+
method && method->isLambdaStaticInvoker()) {
2024+
assert(!method->getParent()->isGenericLambda());
2025+
StrCat("Some");
2026+
PushParen paren(*this);
2027+
ConvertLambdaClosure(method->getParent(),
2028+
method->getParent()->getLambdaCallOperator());
2029+
computed_expr_type_ = ComputedExprType::FreshPointer;
2030+
return;
2031+
}
20152032
StrCat(std::format("Some({})", GetFunctionRefName(fn_decl)));
20162033
computed_expr_type_ = ComputedExprType::FreshPointer;
20172034
}
@@ -2063,7 +2080,11 @@ Converter::CallInfo Converter::CollectCallInfo(clang::CallExpr *expr) {
20632080
unsigned num_named_params =
20642081
function ? function->getNumParams() : proto->getNumParams();
20652082
info.is_variadic = function ? function->isVariadic() : proto->isVariadic();
2066-
info.is_fn_ptr_call = !function || AsLambdaClass(callee->getType());
2083+
info.is_fn_ptr_call =
2084+
!function || AsLambdaClass(callee->getType()) ||
2085+
clang::isa<clang::SubstNonTypeTemplateParmExpr>(
2086+
clang::IgnoreExprNodes(callee, clang::IgnoreParensSingleStep,
2087+
clang::IgnoreImplicitCastsSingleStep));
20672088
info.is_libc_passthrough = RuleRegistry::IsLibcPassthrough(ctx_, expr);
20682089

20692090
for (unsigned i = 0; i < num_named_params && i < num_args; ++i) {
@@ -2224,8 +2245,9 @@ void Converter::EmitArgList(const CallInfo &info) {
22242245

22252246
if (info.is_variadic) {
22262247
if (!info.is_libc_passthrough) {
2227-
StrCat(token::kRef);
2248+
StrCat("Box::new");
22282249
}
2250+
PushParen box(*this, !info.is_libc_passthrough);
22292251
PushBracket push(*this, !info.is_libc_passthrough);
22302252
for (auto *arg : info.variadic_args) {
22312253
{
@@ -3244,6 +3266,13 @@ std::string Converter::ConvertDeclRef(clang::Expr *expr,
32443266
}
32453267

32463268
bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) {
3269+
if (auto param =
3270+
clang::dyn_cast<clang::TemplateParamObjectDecl>(expr->getDecl());
3271+
param && AsLambdaClass(param->getType())) {
3272+
StrCat(GetDefaultAsString(param->getType()));
3273+
computed_expr_type_ = ComputedExprType::FreshValue;
3274+
return false;
3275+
}
32473276
if (auto init = AsLambdaUncapturedConstant(curr_function_, expr)) {
32483277
Convert(init);
32493278
return false;
@@ -4055,6 +4084,9 @@ void Converter::ConvertLambdaClosure(const clang::CXXRecordDecl *decl,
40554084
ConvertVarDeclSkipInit(p);
40564085
StrCat(token::kComma);
40574086
}
4087+
if (call_operator->isVariadic()) {
4088+
StrCat("__args: Box<[VaArg]>", token::kComma);
4089+
}
40584090
in_function_formals_ = false;
40594091
StrCat('|');
40604092
ConvertFunctionReturnType(call_operator);
@@ -4270,10 +4302,6 @@ std::string Converter::GetArrayDefaultAsString(clang::QualType qual_type) {
42704302
std::string Converter::GetDefaultAsString(clang::QualType qual_type) {
42714303
if (auto lambda = AsLambdaClass(qual_type);
42724304
lambda && lambda->captures().empty()) {
4273-
if (HasStaticLocal(lambda->getLambdaCallOperator()->getBody())) {
4274-
llvm::report_fatal_error("default-constructed lambda with a static local "
4275-
"is not supported yet");
4276-
}
42774305
Buffer buf(*this);
42784306
ConvertCapturelessLambda(lambda);
42794307
return std::move(buf).str();
@@ -4616,7 +4644,7 @@ void Converter::ConvertFunctionParameters(clang::FunctionDecl *decl) {
46164644
StrCat(token::kComma);
46174645
}
46184646
if (decl->isVariadic()) {
4619-
StrCat("__args: &[VaArg]", token::kComma);
4647+
StrCat("__args: Box<[VaArg]>", token::kComma);
46204648
}
46214649
in_function_formals_ = false;
46224650
}
@@ -5311,15 +5339,15 @@ Converter::ConvertVariadicTail(clang::Expr *expr,
53115339
unsigned fixed = tgt_ir ? tgt_ir->params.size() : 0;
53125340

53135341
Buffer buf(*this);
5314-
StrCat("&[");
5342+
StrCat("Box::<[VaArg]>::from([");
53155343
for (unsigned i = fixed; i < all_args.size(); ++i) {
53165344
{
53175345
PushParen p(*this);
53185346
ConvertVariadicArg(all_args[i]);
53195347
}
53205348
StrCat(".into()", token::kComma);
53215349
}
5322-
StrCat("]");
5350+
StrCat("])");
53235351
return std::move(buf).str();
53245352
}
53255353

‎cpp2rust/converter/converter.h‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
// Distributed under the MIT license that can be found in the LICENSE file.
55

66
#include <clang/AST/ASTContext.h>
7+
#include <clang/AST/Mangle.h>
78
#include <clang/AST/RecursiveASTVisitor.h>
89
#include <clang/Sema/Sema.h>
910

1011
#include <functional>
1112
#include <map>
13+
#include <memory>
1214
#include <optional>
1315
#include <string>
1416
#include <type_traits>
@@ -32,9 +34,18 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
3234
const char *keyword_unsafe = "unsafe",
3335
const char *keyword_mut = keyword::kMut)
3436
: rs_code_(&rs_code), ctx_(ctx), keyword_unsafe_(keyword_unsafe),
35-
keyword_mut_(keyword_mut) {}
37+
keyword_mut_(keyword_mut) {
38+
if (!GetNameGenerator()) {
39+
name_generator_ = std::make_unique<clang::ASTNameGenerator>(ctx);
40+
SetNameGenerator(name_generator_.get());
41+
}
42+
}
3643

37-
virtual ~Converter() = default;
44+
virtual ~Converter() {
45+
if (name_generator_) {
46+
SetNameGenerator(nullptr);
47+
}
48+
}
3849

3950
Converter(const Converter &) = delete;
4051
Converter &operator=(const Converter &) = delete;
@@ -788,6 +799,7 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
788799

789800
std::string *rs_code_;
790801
clang::ASTContext &ctx_;
802+
std::unique_ptr<clang::ASTNameGenerator> name_generator_;
791803
clang::FunctionDecl *curr_function_ = nullptr;
792804
bool in_function_formals_ = false;
793805
enum class MethodTarget : uint8_t {

‎cpp2rust/converter/converter_lib.cpp‎

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,24 @@ std::string GetNumAsString(llvm::APFloat value) {
296296
bool IsUserDefinedDecl(const clang::Decl *decl) {
297297
const auto &ctx = decl->getASTContext();
298298
const auto &src_mgr = ctx.getSourceManager();
299+
if (auto fn = llvm::dyn_cast<clang::FunctionDecl>(decl)) {
300+
if (const clang::FunctionDecl *definition = nullptr;
301+
fn->isDefined(definition)) {
302+
decl = definition;
303+
} else if (llvm::any_of(fn->redecls(), [&](auto redecl) {
304+
return src_mgr.isInSystemHeader(redecl->getLocation());
305+
})) {
306+
return false;
307+
}
308+
} else if (auto var = llvm::dyn_cast<clang::VarDecl>(decl)) {
309+
if (auto definition = var->getDefinition()) {
310+
decl = definition;
311+
} else if (llvm::any_of(var->redecls(), [&](auto redecl) {
312+
return src_mgr.isInSystemHeader(redecl->getLocation());
313+
})) {
314+
return false;
315+
}
316+
}
299317
auto src_loc = decl->getLocation();
300318
if (auto *spec =
301319
clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(decl);
@@ -822,12 +840,25 @@ static std::string GetParamSignature(const clang::Decl *decl) {
822840
return args;
823841
}
824842

843+
static clang::ASTNameGenerator *name_generator = nullptr;
844+
845+
void SetNameGenerator(clang::ASTNameGenerator *generator) {
846+
name_generator = generator;
847+
}
848+
849+
clang::ASTNameGenerator *GetNameGenerator() { return name_generator; }
850+
851+
static std::string GetMangledName(const clang::Decl *decl) {
852+
assert(name_generator);
853+
return name_generator->getName(decl);
854+
}
855+
825856
static std::string GetLexicalSpecializationID(const clang::Decl *decl) {
826857
auto &ctx = decl->getASTContext();
827858
std::string id;
828859
if (const auto *var =
829860
clang::dyn_cast<clang::VarTemplateSpecializationDecl>(decl)) {
830-
id += clang::ASTNameGenerator(var->getASTContext()).getName(var);
861+
id += GetMangledName(var);
831862
}
832863
if (const auto *self =
833864
clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(decl)) {
@@ -846,7 +877,7 @@ static std::string GetLexicalSpecializationID(const clang::Decl *decl) {
846877
}
847878
if (const auto *fn = clang::dyn_cast<clang::FunctionDecl>(dc);
848879
fn && fn->getTemplateSpecializationArgs()) {
849-
id += clang::ASTNameGenerator(fn->getASTContext()).getName(fn);
880+
id += GetMangledName(fn);
850881
}
851882
}
852883
return id;
@@ -919,9 +950,7 @@ std::string DisambiguateAnonymousTag(const clang::TagDecl *tag) {
919950
static std::unordered_map<std::string, size_t> type_mapping;
920951

921952
static size_t GetDeclId(const clang::NamedDecl *decl, bool internal) {
922-
std::string key =
923-
clang::ASTNameGenerator(decl->getASTContext()).getName(decl) +
924-
GetParamSignature(decl);
953+
std::string key = GetMangledName(decl) + GetParamSignature(decl);
925954
if (internal) {
926955
key += GetLocationID(decl);
927956
}
@@ -982,9 +1011,11 @@ std::string GetNamedDeclAsString(const clang::NamedDecl *decl) {
9821011
target = record;
9831012
}
9841013
}
1014+
auto *record = clang::dyn_cast<clang::CXXRecordDecl>(target);
9851015
return std::format(
986-
"anon_{}", type_mapping.try_emplace(GetID(target), type_mapping.size())
987-
.first->second);
1016+
"{}_{}", record && record->isLambda() ? "lambda" : "anon",
1017+
type_mapping.try_emplace(GetID(target), type_mapping.size())
1018+
.first->second);
9881019
}
9891020

9901021
std::optional<size_t> id;
@@ -1346,21 +1377,6 @@ clang::QualType GetDeclRefType(const clang::FunctionDecl *fn,
13461377
return field ? field->getType() : decl->getType();
13471378
}
13481379

1349-
bool HasStaticLocal(const clang::Stmt *stmt) {
1350-
if (!stmt) {
1351-
return false;
1352-
}
1353-
if (auto decl_stmt = clang::dyn_cast<clang::DeclStmt>(stmt)) {
1354-
for (auto decl : decl_stmt->decls()) {
1355-
if (auto var = clang::dyn_cast<clang::VarDecl>(decl);
1356-
var && var->isStaticLocal()) {
1357-
return true;
1358-
}
1359-
}
1360-
}
1361-
return llvm::any_of(stmt->children(), HasStaticLocal);
1362-
}
1363-
13641380
bool IsUserOperatorCall(const clang::CXXOperatorCallExpr *expr) {
13651381
const auto *callee = expr->getDirectCallee();
13661382
if (!callee || AsLambdaOperatorCall(callee)) {

‎cpp2rust/converter/converter_lib.h‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <clang/AST/Decl.h>
88
#include <clang/AST/DeclCXX.h>
99
#include <clang/AST/Expr.h>
10+
#include <clang/AST/Mangle.h>
1011
#include <clang/AST/StmtCXX.h>
1112
#include <clang/AST/Type.h>
1213
#include <llvm/ADT/APSInt.h>
@@ -181,6 +182,10 @@ unsigned GetColumnNumber(const clang::Decl *decl);
181182

182183
unsigned GetArraySize(clang::QualType array_type);
183184

185+
void SetNameGenerator(clang::ASTNameGenerator *generator);
186+
187+
clang::ASTNameGenerator *GetNameGenerator();
188+
184189
std::string GetID(const clang::Decl *decl);
185190
std::string GetMethodID(const clang::CXXMethodDecl *decl);
186191

@@ -247,8 +252,6 @@ clang::QualType GetDeclRefType(const clang::FunctionDecl *fn,
247252
const clang::Expr *expr,
248253
const clang::ValueDecl *decl);
249254

250-
bool HasStaticLocal(const clang::Stmt *stmt);
251-
252255
bool IsSameTypeComparison(const clang::FunctionDecl *fn,
253256
const clang::CXXRecordDecl *record);
254257

‎cpp2rust/converter/models/converter_refcount.cpp‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1575,6 +1575,12 @@ void ConverterRefCount::ConvertLambdaToFunctionPointer(
15751575

15761576
void ConverterRefCount::ConvertFunctionToFunctionPointer(
15771577
const clang::FunctionDecl *fn_decl) {
1578+
if (auto *method = clang::dyn_cast<clang::CXXMethodDecl>(fn_decl);
1579+
method && method->isLambdaStaticInvoker()) {
1580+
ConvertCapturelessLambda(method->getParent());
1581+
computed_expr_type_ = ComputedExprType::FreshPointer;
1582+
return;
1583+
}
15781584
StrCat(std::format("FnPtr::<{}>::new({})",
15791585
ConvertFunctionPointerType(
15801586
fn_decl->getType()->getAs<clang::FunctionProtoType>()),

‎cpp2rust/converter/rules/rules_loader.cpp‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -394,10 +394,7 @@ std::string ConstructorKey(const std::string &class_key) {
394394
}
395395

396396
std::string FunctionKey(const clang::FunctionDecl *decl) {
397-
if (const clang::FunctionDecl *definition = nullptr;
398-
decl->isDefined(definition) &&
399-
!decl->getASTContext().getSourceManager().isInSystemHeader(
400-
definition->getLocation())) {
397+
if (decl->isDefined() && IsUserDefinedDecl(decl)) {
401398
return {};
402399
}
403400
if (auto method = llvm::dyn_cast<clang::CXXMethodDecl>(decl)) {
@@ -414,6 +411,11 @@ std::string DeclKey(const clang::NamedDecl *decl) {
414411
if (auto fn = decl->getAsFunction()) {
415412
return FunctionKey(fn);
416413
}
414+
if (auto var = llvm::dyn_cast<clang::VarDecl>(decl);
415+
var && var->hasDefinition() != clang::VarDecl::DeclarationOnly &&
416+
IsUserDefinedDecl(var)) {
417+
return {};
418+
}
417419
if (auto record = llvm::dyn_cast<clang::RecordDecl>(decl->getDeclContext())) {
418420
return MemberKey(ClassKey(record), MemberName(decl->getDeclName()));
419421
}

‎docs/src/rules/conventions.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ fails the build; the notes below call out the ones that are not checked.
1111
| Type rule | `t1`, `t2`, ... via `using`/`typedef` | `fn tN() -> RustType` with no arguments |
1212
| Parameters | free-form (`o`, `it`, `key`, `dst`, `n`, ...) | must be `a0`, `a1`, ... consecutive from 0 |
1313
| Generics | `T1`, `T2`, ... (type and non-type params) | `T1`, `T2`, ... consecutive from 1 |
14-
| Variadic pack | `typename... Args` | trailing `va: &[VaArg]` |
14+
| Variadic pack | `typename... Args` | trailing `va: Box<[VaArg]>` |
1515
| Constructing pack | `Init<T, Args> &&...args` | trailing `init: RustType` |
1616
| Locals in Rust bodies | | double-underscore prefix: `__v`, `__fd`, `__e`, ... |
1717

‎docs/src/rules/writing-rules.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ int f1(int a0, int a1, ...) { return fcntl(a0, a1, ...); }
267267

268268
is not expressible. A parameter pack can be forwarded (`args...`), which is
269269
exactly what the rule body needs to do. The Rust side takes a trailing parameter
270-
that must be typed `&[VaArg]` and named `va`:
270+
that must be typed `Box<[VaArg]>` and named `va`:
271271

272272
```cpp
273273
// rules/fcntl/src.cpp
@@ -279,7 +279,7 @@ int f1(int a0, int a1, Args... args) {
279279
280280
```rust
281281
// rules/fcntl/tgt_refcount.rs
282-
fn f1(a0: i32, a1: i32, va: &[VaArg]) -> i32 { ... }
282+
fn f1(a0: i32, a1: i32, va: Box<[VaArg]>) -> i32 { ... }
283283
```
284284

285285
Bodies read the arguments through the va-args API in `libcc2rs` (`VaArg`,

‎docs/src/runtime/va-args.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ sum(3, 10, 20, 30);
3939
```
4040
4141
```rust
42-
pub fn sum_0(count: i32, __args: &[VaArg]) -> i32 {
42+
pub fn sum_0(count: i32, __args: Box<[VaArg]>) -> i32 {
4343
let ap: Value<VaList> = Rc::new(RefCell::new(VaList::default()));
4444
(*ap.borrow_mut()) = VaList::new(__args);
4545
let total: Value<i32> = Rc::new(RefCell::new(0));
@@ -48,7 +48,7 @@ pub fn sum_0(count: i32, __args: &[VaArg]) -> i32 {
4848
// ...
4949
}
5050
51-
sum_0(3, &[10.into(), 20.into(), 30.into()]);
51+
sum_0(3, Box::new([10.into(), 20.into(), 30.into()]));
5252
```
5353

5454
`arg::<T>()` goes through the `VaArgGet` trait, implemented for the integer and
@@ -59,5 +59,5 @@ panics, as does reading past the last argument.
5959

6060
Variadic libc functions such as `printf` and `fcntl` are handled by
6161
[variadic rules](../rules/writing-rules.md#variadic-functions), whose bodies
62-
receive the same `&[VaArg]` slice; `format_c` in the
62+
receive the same `Box<[VaArg]>`; `format_c` in the
6363
[format module](./io.md#formatting) consumes one to evaluate a format string.

0 commit comments

Comments
 (0)