Skip to content

Commit 8e84d83

Browse files
authored
Move function-local records in global scope (#375)
```cpp template <typename T> int get(T t) { return t.x; } int main() { struct Local { int x; }; Local l{7}; assert(get(l) == 7); return 0; } ``` The `get` function template lives in the global scope while `Local` (used to instantiate `get`) lives at function scope. In the AST instantiations live in the global scope as well, so it gets translated as: ```rs // Wrong: the global scope has no Local_1. It only exists inside main pub unsafe fn get_0(mut t: Local_1) -> i32 { return (t.x as i32); } unsafe fn main_0() -> i32 { pub struct Local_1 { pub x: i32, }; let mut l: Local_1 = Local_1 { x: 7 }; assert!(((unsafe { get_0(l,) }) == (7))); return 0; } ``` This PR fixes this by moving the definition of `Local_1` at a global scope: ```rs // Correct: now Local_1 is visible for the instantiation pub unsafe fn get_0(mut t: Local_1) -> i32 { return (t.x as i32); } unsafe fn main_0() -> i32 { let mut l: Local_1 = Local_1 { x: 7 }; assert!(((unsafe { get_0(l,) }) == (7))); return 0; } pub struct Local_1 { pub x: i32, }; ```
1 parent f24c977 commit 8e84d83

21 files changed

Lines changed: 557 additions & 246 deletions

‎cpp2rust/converter/converter.cpp‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,10 @@ bool Converter::VisitTranslationUnitDecl(clang::TranslationUnitDecl *decl) {
363363
if (IsUserDefinedDecl(child) &&
364364
(IsInMainFile(child) || !decl_ids_.contains(GetID(child)))) {
365365
Convert(child);
366+
if (!hoisted_records_.empty()) {
367+
StrCat(hoisted_records_);
368+
hoisted_records_.clear();
369+
}
366370
}
367371
}
368372
return false;
@@ -1257,6 +1261,12 @@ bool Converter::VisitCompoundStmt(clang::CompoundStmt *stmt) {
12571261

12581262
bool Converter::VisitDeclStmt(clang::DeclStmt *stmt) {
12591263
for (auto *decl : stmt->decls()) {
1264+
if (clang::isa<clang::TagDecl>(decl)) {
1265+
Buffer buf(*this);
1266+
Convert(decl);
1267+
hoisted_records_ += std::move(buf).str();
1268+
continue;
1269+
}
12601270
Convert(decl);
12611271
StrCat(token::kSemiColon);
12621272
}

‎cpp2rust/converter/converter.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,8 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
880880
// translation units.
881881
static std::map<std::string, MethodsOnPtr> methods_on_ptr_;
882882

883+
std::string hoisted_records_;
884+
883885
enum class ExprKind : uint8_t {
884886
Callee,
885887
LValue,

‎cpp2rust/converter/converter_lib.cpp‎

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -535,13 +535,24 @@ static std::string GetParamSignature(const clang::Decl *decl) {
535535
}
536536

537537
static std::string GetLexicalSpecializationID(const clang::Decl *decl) {
538+
std::string id;
538539
if (const auto *spec =
539540
clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(
540541
decl->getLexicalDeclContext());
541542
spec && decl->getLexicalDeclContext() != decl->getDeclContext()) {
542-
return Mapper::ToString(Mapper::GetTypeForDecl(spec));
543+
id += Mapper::ToString(Mapper::GetTypeForDecl(spec));
543544
}
544-
return {};
545+
for (const auto *dc = decl->getDeclContext(); dc; dc = dc->getParent()) {
546+
if (const auto *spec =
547+
clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(dc)) {
548+
id += Mapper::ToString(Mapper::GetTypeForDecl(spec));
549+
}
550+
if (const auto *fn = clang::dyn_cast<clang::FunctionDecl>(dc);
551+
fn && fn->getTemplateSpecializationArgs()) {
552+
id += clang::ASTNameGenerator(fn->getASTContext()).getName(fn);
553+
}
554+
}
555+
return id;
545556
}
546557

547558
std::string GetID(const clang::Decl *decl) {
@@ -623,6 +634,10 @@ std::string GetNamedDeclAsString(const clang::NamedDecl *decl) {
623634
var && (var->isFileVarDecl() || var->isStaticLocal())) {
624635
id = GetDeclId(var->getCanonicalDecl(),
625636
var->getFormalLinkage() != clang::Linkage::External);
637+
} else if (auto *tag = clang::dyn_cast<clang::TagDecl>(decl);
638+
tag && tag->getDeclContext()->isFunctionOrMethod()) {
639+
id =
640+
type_mapping.try_emplace(GetID(tag), type_mapping.size()).first->second;
626641
}
627642
if (id) {
628643
name += '_';

‎cpp2rust/converter/mapper.cpp‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,12 @@ std::string ToString(clang::QualType qual_type, ScalarSugar sugar) {
882882
return ToString(clang::cast<clang::NamedDecl>(tag));
883883
}
884884

885+
if (auto *tag = qual_type->getAsTagDecl();
886+
tag && tag->getIdentifier() &&
887+
tag->getDeclContext()->isFunctionOrMethod()) {
888+
return GetNamedDeclAsString(tag);
889+
}
890+
885891
if (auto renamed = DisambiguateAnonymousTag(qual_type->getAsTagDecl());
886892
!renamed.empty()) {
887893
return renamed;
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include <assert.h>
2+
3+
template <typename T> int get(T t) { return t.x; }
4+
5+
namespace ns {
6+
template <typename T> int twice(T t) { return t.x * 2; }
7+
} // namespace ns
8+
9+
template <typename T> int wrap(T v) {
10+
struct Local {
11+
T x;
12+
};
13+
Local l{v};
14+
return get(l);
15+
}
16+
17+
int other() {
18+
struct Local {
19+
long x;
20+
long y;
21+
};
22+
Local l{3, 4};
23+
return get(l) + (int)l.y;
24+
}
25+
26+
int main() {
27+
struct Local {
28+
int x;
29+
};
30+
Local l{7};
31+
assert(get(l) == 7);
32+
assert(ns::twice(l) == 14);
33+
assert(other() == 7);
34+
assert(wrap(5) == 5);
35+
assert(wrap(6L) == 6);
36+
return 0;
37+
}

‎tests/unit/out/refcount/anonymous-struct.rs‎

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -321,36 +321,6 @@ fn main_0() -> i32 {
321321
.borrow())
322322
== 11)
323323
);
324-
#[derive(Default)]
325-
pub struct anon_6 {
326-
pub x: Value<i32>,
327-
pub z: Value<i32>,
328-
}
329-
impl Clone for anon_6 {
330-
fn clone(&self) -> Self {
331-
let __this: Value<anon_6> = Rc::new(RefCell::new(Self {
332-
x: Rc::new(RefCell::new((*self.x.borrow()))),
333-
z: Rc::new(RefCell::new((*self.z.borrow()))),
334-
}));
335-
let this: Ptr<anon_6> = __this.as_pointer();
336-
Rc::try_unwrap(__this).ok().unwrap().into_inner()
337-
}
338-
}
339-
impl ByteRepr for anon_6 {
340-
fn byte_size() -> usize {
341-
8
342-
}
343-
fn to_bytes(&self, buf: &mut [u8]) {
344-
(*self.x.borrow()).to_bytes(&mut buf[0..4]);
345-
(*self.z.borrow()).to_bytes(&mut buf[4..8]);
346-
}
347-
fn from_bytes(buf: &[u8]) -> Self {
348-
Self {
349-
x: Rc::new(RefCell::new(<i32>::from_bytes(&buf[0..4]))),
350-
z: Rc::new(RefCell::new(<i32>::from_bytes(&buf[4..8]))),
351-
}
352-
}
353-
};
354324
let s: Value<anon_6> = Rc::new(RefCell::new(<anon_6>::default()));
355325
(*(*s.borrow()).x.borrow_mut()) = 1;
356326
(*(*s.borrow()).z.borrow_mut()) = 2;
@@ -368,3 +338,33 @@ fn main_0() -> i32 {
368338
);
369339
return 0;
370340
}
341+
#[derive(Default)]
342+
pub struct anon_6 {
343+
pub x: Value<i32>,
344+
pub z: Value<i32>,
345+
}
346+
impl Clone for anon_6 {
347+
fn clone(&self) -> Self {
348+
let __this: Value<anon_6> = Rc::new(RefCell::new(Self {
349+
x: Rc::new(RefCell::new((*self.x.borrow()))),
350+
z: Rc::new(RefCell::new((*self.z.borrow()))),
351+
}));
352+
let this: Ptr<anon_6> = __this.as_pointer();
353+
Rc::try_unwrap(__this).ok().unwrap().into_inner()
354+
}
355+
}
356+
impl ByteRepr for anon_6 {
357+
fn byte_size() -> usize {
358+
8
359+
}
360+
fn to_bytes(&self, buf: &mut [u8]) {
361+
(*self.x.borrow()).to_bytes(&mut buf[0..4]);
362+
(*self.z.borrow()).to_bytes(&mut buf[4..8]);
363+
}
364+
fn from_bytes(buf: &[u8]) -> Self {
365+
Self {
366+
x: Rc::new(RefCell::new(<i32>::from_bytes(&buf[0..4]))),
367+
z: Rc::new(RefCell::new(<i32>::from_bytes(&buf[4..8]))),
368+
}
369+
}
370+
}

‎tests/unit/out/refcount/anonymous-struct_c.rs‎

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -290,34 +290,6 @@ fn main_0() -> i32 {
290290
== 11) as i32)
291291
!= 0)
292292
);
293-
#[derive(Default)]
294-
pub struct anon_6 {
295-
pub x: Value<i32>,
296-
pub z: Value<i32>,
297-
}
298-
impl Clone for anon_6 {
299-
fn clone(&self) -> Self {
300-
Self {
301-
x: Rc::new(RefCell::new((*self.x.borrow()).clone())),
302-
z: Rc::new(RefCell::new((*self.z.borrow()).clone())),
303-
}
304-
}
305-
}
306-
impl ByteRepr for anon_6 {
307-
fn byte_size() -> usize {
308-
8
309-
}
310-
fn to_bytes(&self, buf: &mut [u8]) {
311-
(*self.x.borrow()).to_bytes(&mut buf[0..4]);
312-
(*self.z.borrow()).to_bytes(&mut buf[4..8]);
313-
}
314-
fn from_bytes(buf: &[u8]) -> Self {
315-
Self {
316-
x: Rc::new(RefCell::new(<i32>::from_bytes(&buf[0..4]))),
317-
z: Rc::new(RefCell::new(<i32>::from_bytes(&buf[4..8]))),
318-
}
319-
}
320-
};
321293
let s: Value<anon_6> = <Value<anon_6>>::default();
322294
(*(*s.borrow()).x.borrow_mut()) = 1;
323295
(*(*s.borrow()).z.borrow_mut()) = 2;
@@ -335,3 +307,31 @@ fn main_0() -> i32 {
335307
);
336308
return 0;
337309
}
310+
#[derive(Default)]
311+
pub struct anon_6 {
312+
pub x: Value<i32>,
313+
pub z: Value<i32>,
314+
}
315+
impl Clone for anon_6 {
316+
fn clone(&self) -> Self {
317+
Self {
318+
x: Rc::new(RefCell::new((*self.x.borrow()).clone())),
319+
z: Rc::new(RefCell::new((*self.z.borrow()).clone())),
320+
}
321+
}
322+
}
323+
impl ByteRepr for anon_6 {
324+
fn byte_size() -> usize {
325+
8
326+
}
327+
fn to_bytes(&self, buf: &mut [u8]) {
328+
(*self.x.borrow()).to_bytes(&mut buf[0..4]);
329+
(*self.z.borrow()).to_bytes(&mut buf[4..8]);
330+
}
331+
fn from_bytes(buf: &[u8]) -> Self {
332+
Self {
333+
x: Rc::new(RefCell::new(<i32>::from_bytes(&buf[0..4]))),
334+
z: Rc::new(RefCell::new(<i32>::from_bytes(&buf[4..8]))),
335+
}
336+
}
337+
}

‎tests/unit/out/refcount/anonymous_enum.rs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,6 @@ pub fn main() {
7878
std::process::exit(main_0());
7979
}
8080
fn main_0() -> i32 {
81-
pub type anon_3 = u32;
82-
pub const anon_3_THIRD_A: anon_3 = 0;
83-
pub const anon_3_THIRD_B: anon_3 = 1;;
8481
assert!(((anon_0_FIRST_A as i32) != (anon_0_FIRST_B as i32)));
8582
assert!(((anon_1_SECOND_A as i32) != (anon_1_SECOND_B as i32)));
8683
assert!(((anon_3_THIRD_A as i32) != (anon_3_THIRD_B as i32)));
@@ -95,3 +92,6 @@ fn main_0() -> i32 {
9592
assert!((((*(*w.borrow()).field.borrow()) as i32) == (anon_2_FIELD_B as i32)));
9693
return 0;
9794
}
95+
pub type anon_3 = u32;
96+
pub const anon_3_THIRD_A: anon_3 = 0;
97+
pub const anon_3_THIRD_B: anon_3 = 1;

‎tests/unit/out/refcount/anonymous_enum_c.rs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,6 @@ pub fn main() {
7474
std::process::exit(main_0());
7575
}
7676
fn main_0() -> i32 {
77-
pub type anon_3 = u32;
78-
pub const anon_3_THIRD_A: anon_3 = 0;
79-
pub const anon_3_THIRD_B: anon_3 = 1;;
8077
assert!(((((anon_0_FIRST_A as i32) != (anon_0_FIRST_B as i32)) as i32) != 0));
8178
assert!(((((anon_1_SECOND_A as i32) != (anon_1_SECOND_B as i32)) as i32) != 0));
8279
assert!(((((anon_3_THIRD_A as i32) != (anon_3_THIRD_B as i32)) as i32) != 0));
@@ -97,3 +94,6 @@ fn main_0() -> i32 {
9794
);
9895
return 0;
9996
}
97+
pub type anon_3 = u32;
98+
pub const anon_3_THIRD_A: anon_3 = 0;
99+
pub const anon_3_THIRD_B: anon_3 = 1;

0 commit comments

Comments
 (0)