Skip to content

Commit 943b97c

Browse files
authored
Add Inc and Dec traits for enums (#153)
This implements PostfixInc, PrefixInc, PostfixDec, PrefixDec for all user defined enum types. Instead of generatic more than 30 lines of trait implementations per user-defined enum, I declared a macro in libcc2rs that enums call in order to take care of the actual trait implementation.
1 parent 63df8b2 commit 943b97c

39 files changed

Lines changed: 304 additions & 4 deletions

cpp2rust/converter/converter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2892,6 +2892,7 @@ bool Converter::VisitEnumDecl(clang::EnumDecl *decl) {
28922892
StrCat("}");
28932893

28942894
AddFromImpl(decl);
2895+
AddIncDecImpls(decl);
28952896
return false;
28962897
}
28972898

@@ -2913,6 +2914,10 @@ void Converter::AddFromImpl(clang::EnumDecl *decl) {
29132914
StrCat(std::format("_ => panic!(\"invalid {} value: {{}}\", n),", name));
29142915
}
29152916

2917+
void Converter::AddIncDecImpls(clang::EnumDecl *decl) {
2918+
StrCat(std::format("libcc2rs::impl_enum_inc_dec!({});", GetRecordName(decl)));
2919+
}
2920+
29162921
bool Converter::VisitCXXDefaultArgExpr(clang::CXXDefaultArgExpr *expr) {
29172922
if (expr->getType()->isPointerType()) {
29182923
StrCat(keyword_default_);

cpp2rust/converter/converter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,8 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
315315

316316
virtual void AddFromImpl(clang::EnumDecl *decl);
317317

318+
virtual void AddIncDecImpls(clang::EnumDecl *decl);
319+
318320
virtual bool VisitCXXDefaultArgExpr(clang::CXXDefaultArgExpr *expr);
319321

320322
virtual bool VisitLambdaExpr(clang::LambdaExpr *expr);

libcc2rs/src/inc.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,38 @@ impl<T> UnsafePrefixInc for *mut T {
124124
}
125125
}
126126

127+
#[macro_export]
128+
macro_rules! impl_enum_inc_dec {
129+
($t:ty) => {
130+
impl PostfixInc for $t {
131+
fn postfix_inc(&mut self) -> Self {
132+
let copy = *self;
133+
*self = <$t>::from(*self as i32 + 1);
134+
copy
135+
}
136+
}
137+
impl PrefixInc for $t {
138+
fn prefix_inc(&mut self) -> Self {
139+
*self = <$t>::from(*self as i32 + 1);
140+
*self
141+
}
142+
}
143+
impl PostfixDec for $t {
144+
fn postfix_dec(&mut self) -> Self {
145+
let copy = *self;
146+
*self = <$t>::from(*self as i32 - 1);
147+
copy
148+
}
149+
}
150+
impl PrefixDec for $t {
151+
fn prefix_dec(&mut self) -> Self {
152+
*self = <$t>::from(*self as i32 - 1);
153+
*self
154+
}
155+
}
156+
};
157+
}
158+
127159
#[cfg(test)]
128160
mod tests {
129161
use super::*;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// panic
2+
3+
enum color { RED, GREEN, BLUE };
4+
5+
int main() {
6+
enum color c = BLUE;
7+
c++;
8+
return c == RED ? 0 : 1;
9+
}

tests/ub/out/refcount/enum_out_of_range_cast.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ impl From<i32> for Color {
2323
}
2424
}
2525
}
26+
libcc2rs::impl_enum_inc_dec!(Color);
2627
pub fn main() {
2728
std::process::exit(main_0());
2829
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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+
#[derive(Clone, Copy, PartialEq, Debug, Default)]
10+
enum color {
11+
#[default]
12+
RED = 0,
13+
GREEN = 1,
14+
BLUE = 2,
15+
}
16+
impl From<i32> for color {
17+
fn from(n: i32) -> color {
18+
match n {
19+
0 => color::RED,
20+
1 => color::GREEN,
21+
2 => color::BLUE,
22+
_ => panic!("invalid color value: {}", n),
23+
}
24+
}
25+
}
26+
libcc2rs::impl_enum_inc_dec!(color);
27+
pub fn main() {
28+
std::process::exit(main_0());
29+
}
30+
fn main_0() -> i32 {
31+
let c: Value<color> = Rc::new(RefCell::new(color::BLUE));
32+
(*c.borrow_mut()).postfix_inc();
33+
return if (((((*c.borrow()) as u32) == ((color::RED as i32) as u32)) as i32) != 0) {
34+
0
35+
} else {
36+
1
37+
};
38+
}

tests/ub/out/unsafe/enum_out_of_range_cast.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ impl From<i32> for Color {
2323
}
2424
}
2525
}
26+
libcc2rs::impl_enum_inc_dec!(Color);
2627
pub fn main() {
2728
unsafe {
2829
std::process::exit(main_0() as i32);
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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+
#[derive(Clone, Copy, PartialEq, Debug, Default)]
10+
enum color {
11+
#[default]
12+
RED = 0,
13+
GREEN = 1,
14+
BLUE = 2,
15+
}
16+
impl From<i32> for color {
17+
fn from(n: i32) -> color {
18+
match n {
19+
0 => color::RED,
20+
1 => color::GREEN,
21+
2 => color::BLUE,
22+
_ => panic!("invalid color value: {}", n),
23+
}
24+
}
25+
}
26+
libcc2rs::impl_enum_inc_dec!(color);
27+
pub fn main() {
28+
unsafe {
29+
std::process::exit(main_0() as i32);
30+
}
31+
}
32+
unsafe fn main_0() -> i32 {
33+
let mut c: color = color::BLUE;
34+
c.postfix_inc();
35+
return if ((((c as u32) == ((color::RED as i32) as u32)) as i32) != 0) {
36+
0
37+
} else {
38+
1
39+
};
40+
}

tests/unit/enum_increment.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#include <assert.h>
2+
3+
enum color { RED, GREEN, BLUE, COLOR_LAST };
4+
5+
int main() {
6+
int count = 0;
7+
for (enum color c = RED; c < COLOR_LAST; c++) {
8+
count++;
9+
}
10+
assert(count == 3);
11+
12+
enum color c = RED;
13+
assert(c++ == RED);
14+
assert(++c == BLUE);
15+
assert(c-- == BLUE);
16+
assert(--c == RED);
17+
return 0;
18+
}

tests/unit/out/refcount/anonymous_enum.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ impl From<i32> for anon_enum_3 {
2121
}
2222
}
2323
}
24+
libcc2rs::impl_enum_inc_dec!(anon_enum_3);
2425
#[derive(Clone, Copy, PartialEq, Debug, Default)]
2526
enum anon_enum_11 {
2627
#[default]
@@ -36,6 +37,7 @@ impl From<i32> for anon_enum_11 {
3637
}
3738
}
3839
}
40+
libcc2rs::impl_enum_inc_dec!(anon_enum_11);
3941
#[derive(Default)]
4042
pub struct S {
4143
pub a: Value<i32>,
@@ -73,6 +75,7 @@ impl From<i32> for TdEnum {
7375
}
7476
}
7577
}
78+
libcc2rs::impl_enum_inc_dec!(TdEnum);
7679
#[derive(Clone, Copy, PartialEq, Debug, Default)]
7780
enum anon_enum_24 {
7881
#[default]
@@ -88,6 +91,7 @@ impl From<i32> for anon_enum_24 {
8891
}
8992
}
9093
}
94+
libcc2rs::impl_enum_inc_dec!(anon_enum_24);
9195
#[derive(Default)]
9296
pub struct WithAnonField {
9397
pub a: Value<i32>,
@@ -121,7 +125,8 @@ fn main_0() -> i32 {
121125
_ => panic!("invalid anon_enum_31 value: {}", n),
122126
}
123127
}
124-
};
128+
}
129+
libcc2rs::impl_enum_inc_dec!(anon_enum_31);
125130
assert!(((anon_enum_3::FIRST_A as i32) != (anon_enum_3::FIRST_B as i32)));
126131
assert!(((anon_enum_11::SECOND_A as i32) != (anon_enum_11::SECOND_B as i32)));
127132
assert!(((anon_enum_31::THIRD_A as i32) != (anon_enum_31::THIRD_B as i32)));

0 commit comments

Comments
 (0)