Skip to content

Commit 728b9ae

Browse files
committed
Fix default lambdas with static locals
1 parent b18f36d commit 728b9ae

5 files changed

Lines changed: 172 additions & 21 deletions

File tree

‎cpp2rust/converter/converter.cpp‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,9 @@ bool Converter::ConvertVarDeclSkipInit(clang::VarDecl *decl) {
515515
ENSURE(decl_ids_.insert(GetID(decl)).second);
516516
global_inits_.push_back(ForceGlobalInit(decl));
517517
} else if (decl->isStaticLocal()) {
518+
if (!globals_.insert(name).second) {
519+
return false;
520+
}
518521
StrCat(keyword::kStatic, keyword_mut_);
519522
} else if (decl->isLocalVarDecl()) {
520523
StrCat(keyword::kLet);
@@ -4281,10 +4284,6 @@ std::string Converter::GetArrayDefaultAsString(clang::QualType qual_type) {
42814284
std::string Converter::GetDefaultAsString(clang::QualType qual_type) {
42824285
if (auto lambda = AsLambdaClass(qual_type);
42834286
lambda && lambda->captures().empty()) {
4284-
if (HasStaticLocal(lambda->getLambdaCallOperator()->getBody())) {
4285-
llvm::report_fatal_error("default-constructed lambda with a static local "
4286-
"is not supported yet");
4287-
}
42884287
Buffer buf(*this);
42894288
ConvertCapturelessLambda(lambda);
42904289
return std::move(buf).str();

‎cpp2rust/converter/converter_lib.cpp‎

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,21 +1377,6 @@ clang::QualType GetDeclRefType(const clang::FunctionDecl *fn,
13771377
return field ? field->getType() : decl->getType();
13781378
}
13791379

1380-
bool HasStaticLocal(const clang::Stmt *stmt) {
1381-
if (!stmt) {
1382-
return false;
1383-
}
1384-
if (auto decl_stmt = clang::dyn_cast<clang::DeclStmt>(stmt)) {
1385-
for (auto decl : decl_stmt->decls()) {
1386-
if (auto var = clang::dyn_cast<clang::VarDecl>(decl);
1387-
var && var->isStaticLocal()) {
1388-
return true;
1389-
}
1390-
}
1391-
}
1392-
return llvm::any_of(stmt->children(), HasStaticLocal);
1393-
}
1394-
13951380
bool IsUserOperatorCall(const clang::CXXOperatorCallExpr *expr) {
13961381
const auto *callee = expr->getDirectCallee();
13971382
if (!callee || AsLambdaOperatorCall(callee)) {

‎cpp2rust/converter/converter_lib.h‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,6 @@ clang::QualType GetDeclRefType(const clang::FunctionDecl *fn,
252252
const clang::Expr *expr,
253253
const clang::ValueDecl *decl);
254254

255-
bool HasStaticLocal(const clang::Stmt *stmt);
256-
257255
bool IsSameTypeComparison(const clang::FunctionDecl *fn,
258256
const clang::CXXRecordDecl *record);
259257

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
extern crate libcc2rs;
2+
use libcc2rs::*;
3+
use std::cell::RefCell;
4+
use std::collections::BTreeMap;
5+
use std::io::prelude::*;
6+
use std::io::{Read, Seek, Write};
7+
use std::os::fd::AsFd;
8+
use std::rc::{Rc, Weak};
9+
thread_local!(
10+
pub static a_0: Value<i32> = Rc::new(RefCell::new(0_i32));
11+
);
12+
pub fn main() {
13+
__cpp2rust_init_globals();
14+
std::process::exit(main_0());
15+
}
16+
fn main_0() -> i32 {
17+
let next: Value<FnPtr<fn() -> i32>> =
18+
Rc::new(RefCell::new(FnPtr::<fn() -> i32>::new(|| -> i32 {
19+
{
20+
return (*n_1.with(Value::clone).borrow_mut()).prefix_inc();
21+
}
22+
})));
23+
assert!((({ (*next.borrow()).call() }) == 1));
24+
assert!((({ (*next.borrow()).call() }) == 2));
25+
let copy: Value<FnPtr<fn() -> i32>> = Rc::new(RefCell::new((*next.borrow()).copy_from()));
26+
assert!((({ (*copy.borrow()).call() }) == 3));
27+
assert!((({ (*next.borrow()).call() }) == 4));
28+
let fresh: Value<FnPtr<fn() -> i32>> =
29+
Rc::new(RefCell::new(FnPtr::<fn() -> i32>::new(|| -> i32 {
30+
{
31+
return (*n_1.with(Value::clone).borrow_mut()).prefix_inc();
32+
}
33+
})));
34+
assert!((({ (*fresh.borrow()).call() }) == 5));
35+
assert!((({ (*next.borrow()).call() }) == 6));
36+
let per_type: Value<FnPtr<Generic>> = Rc::new(RefCell::new(lambda!(
37+
Generic,
38+
{},
39+
|mut x: i32| -> i32 {
40+
(*calls_2.with(Value::clone).borrow_mut()).postfix_inc();
41+
return calls_2.with(|rc| *rc.borrow());
42+
},
43+
|mut x: f64| -> i32 {
44+
(*calls_3.with(Value::clone).borrow_mut()).postfix_inc();
45+
return calls_3.with(|rc| *rc.borrow());
46+
}
47+
)));
48+
assert!((({ (*per_type.borrow()).spec::<fn(i32) -> i32>(0).call(1,) }) == 1));
49+
assert!((({ (*per_type.borrow()).spec::<fn(i32) -> i32>(0).call(2,) }) == 2));
50+
assert!((({ (*per_type.borrow()).spec::<fn(f64) -> i32>(1).call(1_f64,) }) == 1));
51+
assert!((({ (*per_type.borrow()).spec::<fn(i32) -> i32>(0).call(3,) }) == 3));
52+
let read: Value<FnPtr<fn(i32) -> i32>> = Rc::new(RefCell::new(FnPtr::<fn(i32) -> i32>::new(
53+
|mut _a0: i32| -> i32 {
54+
{
55+
return a_0.with(|rc| *rc.borrow());
56+
}
57+
},
58+
)));
59+
assert!((({ (*read.borrow()).call(0,) }) == 0));
60+
a_0.with(|rc| *rc.borrow_mut() = 1);
61+
assert!((({ (*read.borrow()).call(0,) }) == 1));
62+
let local: Value<FnPtr<fn() -> i32>> =
63+
Rc::new(RefCell::new(FnPtr::<fn() -> i32>::new(|| -> i32 {
64+
{
65+
let mut p: P_4 = P_4 { x: 2, y: 3 };
66+
return (p.x * p.y);
67+
}
68+
})));
69+
assert!((({ (*local.borrow()).call() }) == 6));
70+
return 0;
71+
}
72+
thread_local!(
73+
static n_1: Value<i32> = Rc::new(RefCell::new(0));
74+
);
75+
thread_local!(
76+
static calls_2: Value<i32> = Rc::new(RefCell::new(0));
77+
);
78+
thread_local!(
79+
static calls_3: Value<i32> = Rc::new(RefCell::new(0));
80+
);
81+
#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)]
82+
#[byte_size(8)]
83+
pub struct P_4 {
84+
#[offset(0)]
85+
pub x: i32,
86+
#[offset(4)]
87+
pub y: i32,
88+
}
89+
pub fn __cpp2rust_init_globals() {
90+
let _ = a_0.with(|_| ());
91+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
extern crate libc;
2+
use libc::*;
3+
extern crate libcc2rs;
4+
use libcc2rs::*;
5+
use std::collections::BTreeMap;
6+
use std::io::{Read, Seek, Write};
7+
use std::os::fd::{AsFd, FromRawFd, IntoRawFd};
8+
use std::rc::Rc;
9+
pub static mut a_0: std::cell::LazyCell<i32> = std::cell::LazyCell::new(|| unsafe { 0_i32 });
10+
pub fn main() {
11+
unsafe {
12+
__cpp2rust_init_globals();
13+
std::process::exit(main_0() as i32);
14+
}
15+
}
16+
unsafe fn main_0() -> i32 {
17+
let mut next: FnPtr<fn() -> i32> = FnPtr::<fn() -> i32>::new(|| -> i32 {
18+
unsafe {
19+
return (*std::cell::LazyCell::force_mut(&mut *&raw mut n_1)).prefix_inc();
20+
}
21+
});
22+
assert!(((unsafe { next.call() }) == (1)));
23+
assert!(((unsafe { next.call() }) == (2)));
24+
let mut copy: FnPtr<fn() -> i32> = next.copy_from();
25+
assert!(((unsafe { copy.call() }) == (3)));
26+
assert!(((unsafe { next.call() }) == (4)));
27+
let mut fresh: FnPtr<fn() -> i32> = FnPtr::<fn() -> i32>::new(|| -> i32 {
28+
unsafe {
29+
return (*std::cell::LazyCell::force_mut(&mut *&raw mut n_1)).prefix_inc();
30+
}
31+
});
32+
assert!(((unsafe { fresh.call() }) == (5)));
33+
assert!(((unsafe { next.call() }) == (6)));
34+
let mut per_type: FnPtr<Generic> = lambda_unsafe!(
35+
Generic,
36+
{},
37+
|mut x: i32| -> i32 {
38+
(*std::cell::LazyCell::force_mut(&mut *&raw mut calls_2)).postfix_inc();
39+
return (*std::cell::LazyCell::force_mut(&mut *&raw mut calls_2));
40+
},
41+
|mut x: f64| -> i32 {
42+
(*std::cell::LazyCell::force_mut(&mut *&raw mut calls_3)).postfix_inc();
43+
return (*std::cell::LazyCell::force_mut(&mut *&raw mut calls_3));
44+
}
45+
);
46+
assert!(((unsafe { per_type.spec::<fn(i32) -> i32>(0).call(1,) }) == (1)));
47+
assert!(((unsafe { per_type.spec::<fn(i32) -> i32>(0).call(2,) }) == (2)));
48+
assert!(((unsafe { per_type.spec::<fn(f64) -> i32>(1).call(1_f64,) }) == (1)));
49+
assert!(((unsafe { per_type.spec::<fn(i32) -> i32>(0).call(3,) }) == (3)));
50+
let mut read: FnPtr<fn(i32) -> i32> = FnPtr::<fn(i32) -> i32>::new(|mut _a0: i32| -> i32 {
51+
unsafe {
52+
return (*std::cell::LazyCell::force_mut(&mut *&raw mut a_0));
53+
}
54+
});
55+
assert!(((unsafe { read.call(0,) }) == (0)));
56+
(*std::cell::LazyCell::force_mut(&mut *&raw mut a_0)) = 1;
57+
assert!(((unsafe { read.call(0,) }) == (1)));
58+
let mut local: FnPtr<fn() -> i32> = FnPtr::<fn() -> i32>::new(|| -> i32 {
59+
unsafe {
60+
let mut p: P_4 = P_4 { x: 2, y: 3 };
61+
return ((p.x) * (p.y));
62+
}
63+
});
64+
assert!(((unsafe { local.call() }) == (6)));
65+
return 0;
66+
}
67+
static mut n_1: std::cell::LazyCell<i32> = std::cell::LazyCell::new(|| unsafe { 0 });
68+
static mut calls_2: std::cell::LazyCell<i32> = std::cell::LazyCell::new(|| unsafe { 0 });
69+
static mut calls_3: std::cell::LazyCell<i32> = std::cell::LazyCell::new(|| unsafe { 0 });
70+
#[repr(C)]
71+
#[derive(Copy, Clone, VaArg, FnPtrArg, Default)]
72+
pub struct P_4 {
73+
pub x: i32,
74+
pub y: i32,
75+
}
76+
pub unsafe fn __cpp2rust_init_globals() {
77+
std::cell::LazyCell::force(&*&raw const a_0);
78+
}

0 commit comments

Comments
 (0)