Skip to content

Commit 34f0cdd

Browse files
authored
Track current break target using a stack (#29)
1 parent 2340d75 commit 34f0cdd

15 files changed

Lines changed: 42 additions & 20 deletions

cpp2rust/converter/converter.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,7 @@ bool Converter::VisitIfStmt(clang::IfStmt *stmt) {
990990
}
991991

992992
bool Converter::VisitWhileStmt(clang::WhileStmt *stmt) {
993+
PushBreakTarget push(break_target_, BreakTarget::Loop);
993994
StrCat("'loop_:");
994995
StrCat(keyword::kWhile);
995996
ConvertCondition(stmt->getCond());
@@ -1002,6 +1003,7 @@ bool Converter::VisitWhileStmt(clang::WhileStmt *stmt) {
10021003
}
10031004

10041005
bool Converter::VisitDoStmt(clang::DoStmt *stmt) {
1006+
PushBreakTarget push(break_target_, BreakTarget::Loop);
10051007
StrCat("'loop_:");
10061008
StrCat(keyword::kLoop, token::kOpenCurlyBracket);
10071009
curr_for_inc_.emplace(nullptr);
@@ -1016,6 +1018,7 @@ bool Converter::VisitDoStmt(clang::DoStmt *stmt) {
10161018
}
10171019

10181020
bool Converter::VisitForStmt(clang::ForStmt *stmt) {
1021+
PushBreakTarget push(break_target_, BreakTarget::Loop);
10191022
Convert(stmt->getInit());
10201023
StrCat("'loop_:");
10211024
StrCat(keyword::kWhile);
@@ -1055,6 +1058,7 @@ void Converter::ConvertLoopVariable(clang::VarDecl *decl,
10551058

10561059
void Converter::ConvertForRangeBody(clang::CXXForRangeStmt *stmt,
10571060
const clang::VarDecl *map_iter_decl) {
1061+
PushBreakTarget push(break_target_, BreakTarget::Loop);
10581062
std::optional<ScopedMapIterDecl> skip;
10591063
if (map_iter_decl)
10601064
skip.emplace(*this, map_iter_decl);
@@ -1137,7 +1141,7 @@ bool Converter::VisitCXXForRangeStmtIndexBased(clang::CXXForRangeStmt *stmt,
11371141

11381142
bool Converter::VisitBreakStmt([[maybe_unused]] clang::BreakStmt *stmt) {
11391143
StrCat(keyword::kBreak);
1140-
if (break_with_explicit_label_) {
1144+
if (isSwitchBreak()) {
11411145
StrCat("'switch");
11421146
}
11431147
return false;
@@ -2644,6 +2648,7 @@ bool Converter::VisitSwitchCase(clang::SwitchCase *stmt) {
26442648
}
26452649

26462650
bool Converter::VisitSwitchStmt(clang::SwitchStmt *stmt) {
2651+
PushBreakTarget push(break_target_, BreakTarget::Switch);
26472652
StrCat("'switch: {");
26482653
StrCat(std::format("let __match_cond = {};", ToString(stmt->getCond())));
26492654
StrCat("match __match_cond");
@@ -2653,7 +2658,6 @@ bool Converter::VisitSwitchStmt(clang::SwitchStmt *stmt) {
26532658
auto body = llvm::cast<clang::CompoundStmt>(stmt->getBody());
26542659
assert(body);
26552660

2656-
break_with_explicit_label_ = true;
26572661
for (auto it = body->body_begin(), end = body->body_end(); it != end;) {
26582662
if (auto switch_case = clang::dyn_cast<clang::SwitchCase>(*it)) {
26592663
if (clang::isa<clang::CaseStmt>(switch_case)) {
@@ -2676,7 +2680,6 @@ bool Converter::VisitSwitchStmt(clang::SwitchStmt *stmt) {
26762680
if (!has_default_case) {
26772681
StrCat(R"( _ => {})");
26782682
}
2679-
break_with_explicit_label_ = false;
26802683

26812684
StrCat("}");
26822685
StrCat("}");

cpp2rust/converter/converter.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,10 +463,30 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
463463
clang::ASTContext &ctx_;
464464
clang::FunctionDecl *curr_function_ = nullptr;
465465
bool in_function_formals_ = false;
466-
bool break_with_explicit_label_ = false;
467466
std::stack<clang::Expr *> curr_for_inc_;
468467
std::stack<clang::QualType> curr_init_type_;
469468

469+
enum class BreakTarget { Loop, Switch };
470+
std::stack<BreakTarget> break_target_;
471+
472+
bool isSwitchBreak() const {
473+
return !break_target_.empty() && break_target_.top() == BreakTarget::Switch;
474+
}
475+
476+
class PushBreakTarget {
477+
public:
478+
PushBreakTarget(std::stack<BreakTarget> &stack, BreakTarget target)
479+
: stack_(stack) {
480+
stack_.push(target);
481+
}
482+
~PushBreakTarget() { stack_.pop(); }
483+
PushBreakTarget(const PushBreakTarget &) = delete;
484+
PushBreakTarget &operator=(const PushBreakTarget &) = delete;
485+
486+
private:
487+
std::stack<BreakTarget> &stack_;
488+
};
489+
470490
std::unordered_set<const clang::VarDecl *> map_iter_decls_;
471491

472492
struct ScopedMapIterDecl {

tests/lit/lit/formats/Cpp2RustTest.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ def fail(str, code = fail_code):
115115
return lit.Test.XFAIL, ''
116116
return fail('cpp2rust failed\n' + err)
117117

118+
if should_not_translate:
119+
return fail('expected translation-fail but cpp2rust succeeded')
120+
118121
expected_file = self.getExpectedFile(filepath, model, fname)
119122
if not os.path.exists(expected_file) and not replace_expected:
120123
return fail('no expected file')

tests/unit/out/refcount/switch_for_in_switch_break.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub fn for_in_switch_break_0(n: i32) -> i32 {
1616
let i: Value<i32> = Rc::new(RefCell::new(0));
1717
'loop_: while ((*i.borrow()) < 10) {
1818
if ((*i.borrow()) == 3) {
19-
break 'switch;
19+
break;
2020
}
2121
(*r.borrow_mut()) += (*i.borrow());
2222
(*i.borrow_mut()).prefix_inc();

tests/unit/out/refcount/switch_for_switch_for_break.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub fn for_switch_for_break_0(n: i32) -> i32 {
1818
let j: Value<i32> = Rc::new(RefCell::new(0));
1919
'loop_: while ((*j.borrow()) < 10) {
2020
if ((*j.borrow()) == 2) {
21-
break 'switch;
21+
break;
2222
}
2323
(*r.borrow_mut()) += 1;
2424
(*j.borrow_mut()).prefix_inc();

tests/unit/out/refcount/switch_nested.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ pub fn nested_0(a: i32, b: i32) -> i32 {
3232
}
3333
};
3434
(*r.borrow_mut()) += 1;
35-
break;
35+
break 'switch;
3636
}
3737
v if v == 2 => {
3838
(*r.borrow_mut()) = 2;
39-
break;
39+
break 'switch;
4040
}
4141
_ => {
4242
(*r.borrow_mut()) = -1_i32;
43-
break;
43+
break 'switch;
4444
}
4545
}
4646
};

tests/unit/out/refcount/switch_while_in_switch_break.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub fn while_in_switch_break_0(n: i32) -> i32 {
1616
let i: Value<i32> = Rc::new(RefCell::new(0));
1717
'loop_: while ((*i.borrow()) < 10) {
1818
if ((*i.borrow()) == 4) {
19-
break 'switch;
19+
break;
2020
}
2121
(*r.borrow_mut()) += (*i.borrow());
2222
(*i.borrow_mut()).prefix_inc();

tests/unit/out/unsafe/switch_for_in_switch_break.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub unsafe fn for_in_switch_break_0(mut n: i32) -> i32 {
1515
let mut i: i32 = 0;
1616
'loop_: while ((i) < (10)) {
1717
if ((i) == (3)) {
18-
break 'switch;
18+
break;
1919
}
2020
r += i;
2121
i.prefix_inc();

tests/unit/out/unsafe/switch_for_switch_for_break.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub unsafe fn for_switch_for_break_0(mut n: i32) -> i32 {
1717
let mut j: i32 = 0;
1818
'loop_: while ((j) < (10)) {
1919
if ((j) == (2)) {
20-
break 'switch;
20+
break;
2121
}
2222
r += 1;
2323
j.prefix_inc();

tests/unit/out/unsafe/switch_nested.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,15 @@ pub unsafe fn nested_0(mut a: i32, mut b: i32) -> i32 {
3030
}
3131
};
3232
r += 1;
33-
break;
33+
break 'switch;
3434
}
3535
v if v == 2 => {
3636
r = 2;
37-
break;
37+
break 'switch;
3838
}
3939
_ => {
4040
r = -1_i32;
41-
break;
41+
break 'switch;
4242
}
4343
}
4444
};

0 commit comments

Comments
 (0)