diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index ec3fca19..0bac32da 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -2672,7 +2672,7 @@ bool Converter::VisitEnumDecl(clang::EnumDecl *decl) { } Mapper::AddRuleForUserDefinedType(decl); StrCat("#[derive(Clone, Copy, PartialEq, Debug, Default)]"); - StrCat(std::format("enum {}", Mapper::Map(ctx_.getCanonicalTagType(decl)))); + StrCat(std::format("enum {}", GetRecordName(decl))); StrCat("{"); bool first_enumerator = true; for (auto e : decl->enumerators()) { diff --git a/cpp2rust/converter/mapper.cpp b/cpp2rust/converter/mapper.cpp index 45d88bae..fb160715 100644 --- a/cpp2rust/converter/mapper.cpp +++ b/cpp2rust/converter/mapper.cpp @@ -724,6 +724,11 @@ std::string ToString(clang::QualType qual_type) { } } + if (auto *tag = qual_type->getAsTagDecl(); + tag && !tag->getIdentifier() && !tag->getTypedefNameForAnonDecl()) { + return ToString(clang::cast(tag)); + } + std::string type; llvm::raw_string_ostream os(type); normalizeQualType(qual_type).print(os, getPrintPolicy()); @@ -736,6 +741,12 @@ std::string ToString(const clang::NamedDecl *decl) { return synthesizeAnonRecordName(record); } + if (auto *enum_decl = clang::dyn_cast(decl); + enum_decl && !enum_decl->getIdentifier() && + !enum_decl->getTypedefNameForAnonDecl()) { + return std::format("anon_enum_{}", GetLineNumber(enum_decl)); + } + std::string out; llvm::raw_string_ostream os(out); diff --git a/tests/unit/anonymous_enum.cpp b/tests/unit/anonymous_enum.cpp new file mode 100644 index 00000000..3ec0e86e --- /dev/null +++ b/tests/unit/anonymous_enum.cpp @@ -0,0 +1,52 @@ +#include + +enum { + FIRST_A, + FIRST_B, +}; + +struct S { + int a; + + enum { + SECOND_A, + SECOND_B, + }; +}; + +typedef enum { + TD_A, + TD_B, +} TdEnum; + +struct WithAnonField { + int a; + enum { + FIELD_A, + FIELD_B, + } field; +}; + +int main() { + enum { + THIRD_A, + THIRD_B, + }; + + assert(FIRST_A != FIRST_B); + assert(S::SECOND_A != S::SECOND_B); + assert(THIRD_A != THIRD_B); + + TdEnum td = TD_A; + assert(td == TD_A); + td = TD_B; + assert(td == TD_B); + + WithAnonField w; + w.field = WithAnonField::FIELD_A; + assert(w.field == WithAnonField::FIELD_A); + w.field = WithAnonField::FIELD_B; + assert(w.field == WithAnonField::FIELD_B); + + return 0; +}; diff --git a/tests/unit/anonymous_enum_c.c b/tests/unit/anonymous_enum_c.c new file mode 100644 index 00000000..5a2d0c12 --- /dev/null +++ b/tests/unit/anonymous_enum_c.c @@ -0,0 +1,52 @@ +#include + +enum { + FIRST_A, + FIRST_B, +}; + +struct S { + int a; + + enum { + SECOND_A, + SECOND_B, + }; +}; + +typedef enum { + TD_A, + TD_B, +} TdEnum; + +struct WithAnonField { + int a; + enum { + FIELD_A, + FIELD_B, + } field; +}; + +int main() { + enum { + THIRD_A, + THIRD_B, + }; + + assert(FIRST_A != FIRST_B); + assert(SECOND_A != SECOND_B); + assert(THIRD_A != THIRD_B); + + TdEnum td = TD_A; + assert(td == TD_A); + td = TD_B; + assert(td == TD_B); + + struct WithAnonField w; + w.field = FIELD_A; + assert(w.field == FIELD_A); + w.field = FIELD_B; + assert(w.field == FIELD_B); + + return 0; +}; diff --git a/tests/unit/out/refcount/anonymous_enum.rs b/tests/unit/out/refcount/anonymous_enum.rs new file mode 100644 index 00000000..47dcf325 --- /dev/null +++ b/tests/unit/out/refcount/anonymous_enum.rs @@ -0,0 +1,84 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum anon_enum_3 { + #[default] + FIRST_A = 0, + FIRST_B = 1, +} +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum anon_enum_11 { + #[default] + SECOND_A = 0, + SECOND_B = 1, +} +#[derive(Default)] +pub struct S { + pub a: Value, +} +impl Clone for S { + fn clone(&self) -> Self { + let mut this = Self { + a: Rc::new(RefCell::new((*self.a.borrow()))), + }; + this + } +} +impl ByteRepr for S {} +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum TdEnum { + #[default] + TD_A = 0, + TD_B = 1, +} +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum anon_enum_24 { + #[default] + FIELD_A = 0, + FIELD_B = 1, +} +#[derive(Default)] +pub struct WithAnonField { + pub a: Value, + pub field: Value, +} +impl Clone for WithAnonField { + fn clone(&self) -> Self { + let mut this = Self { + a: Rc::new(RefCell::new((*self.a.borrow()))), + field: Rc::new(RefCell::new((*self.field.borrow()).clone())), + }; + this + } +} +impl ByteRepr for WithAnonField {} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + #[derive(Clone, Copy, PartialEq, Debug, Default)] + enum anon_enum_31 { + #[default] + THIRD_A = 0, + THIRD_B = 1, + }; + assert!(((anon_enum_3::FIRST_A as i32) != (anon_enum_3::FIRST_B as i32))); + assert!(((anon_enum_11::SECOND_A as i32) != (anon_enum_11::SECOND_B as i32))); + assert!(((anon_enum_31::THIRD_A as i32) != (anon_enum_31::THIRD_B as i32))); + let td: Value = Rc::new(RefCell::new(TdEnum::TD_A)); + assert!((((*td.borrow()) as i32) == (TdEnum::TD_A as i32))); + (*td.borrow_mut()) = TdEnum::TD_B; + assert!((((*td.borrow()) as i32) == (TdEnum::TD_B as i32))); + let w: Value = Rc::new(RefCell::new(::default())); + (*(*w.borrow()).field.borrow_mut()) = anon_enum_24::FIELD_A; + assert!((((*(*w.borrow()).field.borrow()) as i32) == (anon_enum_24::FIELD_A as i32))); + (*(*w.borrow()).field.borrow_mut()) = anon_enum_24::FIELD_B; + assert!((((*(*w.borrow()).field.borrow()) as i32) == (anon_enum_24::FIELD_B as i32))); + return 0; +} diff --git a/tests/unit/out/refcount/anonymous_enum_c.rs b/tests/unit/out/refcount/anonymous_enum_c.rs new file mode 100644 index 00000000..0b0c762c --- /dev/null +++ b/tests/unit/out/refcount/anonymous_enum_c.rs @@ -0,0 +1,67 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum anon_enum_3 { + #[default] + FIRST_A = 0, + FIRST_B = 1, +} +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum anon_enum_11 { + #[default] + SECOND_A = 0, + SECOND_B = 1, +} +#[derive(Default)] +pub struct S { + pub a: Value, +} +impl ByteRepr for S {} +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum TdEnum { + #[default] + TD_A = 0, + TD_B = 1, +} +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum anon_enum_24 { + #[default] + FIELD_A = 0, + FIELD_B = 1, +} +#[derive(Default)] +pub struct WithAnonField { + pub a: Value, + pub field: Value, +} +impl ByteRepr for WithAnonField {} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + #[derive(Clone, Copy, PartialEq, Debug, Default)] + enum anon_enum_31 { + #[default] + THIRD_A = 0, + THIRD_B = 1, + }; + assert!((anon_enum_3::FIRST_A != anon_enum_3::FIRST_B)); + assert!((anon_enum_11::SECOND_A != anon_enum_11::SECOND_B)); + assert!((anon_enum_31::THIRD_A != anon_enum_31::THIRD_B)); + let td: Value = Rc::new(RefCell::new((TdEnum::TD_A as TdEnum))); + assert!((((*td.borrow()) as u32) == (TdEnum::TD_A as u32))); + (*td.borrow_mut()) = (TdEnum::TD_B as TdEnum); + assert!((((*td.borrow()) as u32) == (TdEnum::TD_B as u32))); + let w: Value = >::default(); + (*(*w.borrow()).field.borrow_mut()) = (anon_enum_24::FIELD_A as anon_enum_24); + assert!((((*(*w.borrow()).field.borrow()) as u32) == (anon_enum_24::FIELD_A as u32))); + (*(*w.borrow()).field.borrow_mut()) = (anon_enum_24::FIELD_B as anon_enum_24); + assert!((((*(*w.borrow()).field.borrow()) as u32) == (anon_enum_24::FIELD_B as u32))); + return 0; +} diff --git a/tests/unit/out/unsafe/anonymous_enum.rs b/tests/unit/out/unsafe/anonymous_enum.rs new file mode 100644 index 00000000..a327b394 --- /dev/null +++ b/tests/unit/out/unsafe/anonymous_enum.rs @@ -0,0 +1,69 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum anon_enum_3 { + #[default] + FIRST_A = 0, + FIRST_B = 1, +} +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum anon_enum_11 { + #[default] + SECOND_A = 0, + SECOND_B = 1, +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct S { + pub a: i32, +} +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum TdEnum { + #[default] + TD_A = 0, + TD_B = 1, +} +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum anon_enum_24 { + #[default] + FIELD_A = 0, + FIELD_B = 1, +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct WithAnonField { + pub a: i32, + pub field: anon_enum_24, +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + #[derive(Clone, Copy, PartialEq, Debug, Default)] + enum anon_enum_31 { + #[default] + THIRD_A = 0, + THIRD_B = 1, + }; + assert!(((anon_enum_3::FIRST_A as i32) != (anon_enum_3::FIRST_B as i32))); + assert!(((anon_enum_11::SECOND_A as i32) != (anon_enum_11::SECOND_B as i32))); + assert!(((anon_enum_31::THIRD_A as i32) != (anon_enum_31::THIRD_B as i32))); + let mut td: TdEnum = TdEnum::TD_A; + assert!(((td as i32) == (TdEnum::TD_A as i32))); + td = (TdEnum::TD_B).clone(); + assert!(((td as i32) == (TdEnum::TD_B as i32))); + let mut w: WithAnonField = ::default(); + w.field = anon_enum_24::FIELD_A; + assert!(((w.field as i32) == (anon_enum_24::FIELD_A as i32))); + w.field = (anon_enum_24::FIELD_B).clone(); + assert!(((w.field as i32) == (anon_enum_24::FIELD_B as i32))); + return 0; +} diff --git a/tests/unit/out/unsafe/anonymous_enum_c.rs b/tests/unit/out/unsafe/anonymous_enum_c.rs new file mode 100644 index 00000000..881be82d --- /dev/null +++ b/tests/unit/out/unsafe/anonymous_enum_c.rs @@ -0,0 +1,69 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum anon_enum_3 { + #[default] + FIRST_A = 0, + FIRST_B = 1, +} +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum anon_enum_11 { + #[default] + SECOND_A = 0, + SECOND_B = 1, +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct S { + pub a: i32, +} +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum TdEnum { + #[default] + TD_A = 0, + TD_B = 1, +} +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum anon_enum_24 { + #[default] + FIELD_A = 0, + FIELD_B = 1, +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct WithAnonField { + pub a: i32, + pub field: anon_enum_24, +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + #[derive(Clone, Copy, PartialEq, Debug, Default)] + enum anon_enum_31 { + #[default] + THIRD_A = 0, + THIRD_B = 1, + }; + assert!(((anon_enum_3::FIRST_A) != (anon_enum_3::FIRST_B))); + assert!(((anon_enum_11::SECOND_A) != (anon_enum_11::SECOND_B))); + assert!(((anon_enum_31::THIRD_A) != (anon_enum_31::THIRD_B))); + let mut td: TdEnum = (TdEnum::TD_A as TdEnum); + assert!(((td as u32) == (TdEnum::TD_A as u32))); + td = (TdEnum::TD_B as TdEnum).clone(); + assert!(((td as u32) == (TdEnum::TD_B as u32))); + let mut w: WithAnonField = ::default(); + w.field = (anon_enum_24::FIELD_A as anon_enum_24); + assert!(((w.field as u32) == (anon_enum_24::FIELD_A as u32))); + w.field = (anon_enum_24::FIELD_B as anon_enum_24).clone(); + assert!(((w.field as u32) == (anon_enum_24::FIELD_B as u32))); + return 0; +}