Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions cpp2rust/converter/converter_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,31 @@ std::string GetID(const clang::Decl *decl) {
return GetLocationID(decl) + GetParamSignature(decl);
}

std::string DisambiguateAnonymousTag(const clang::TagDecl *tag) {
if (!tag) {
return "";
}
// C++ does not allow collision between tags and typedef identifiers.
if (tag->getASTContext().getLangOpts().CPlusPlus) {
return "";
}
// Tag has an identifier, nothing to disambiguate.
if (tag->getIdentifier()) {
return "";
}
// The anonymous decl is named through a typedef; guards getName() below.
auto typedef_decl = tag->getTypedefNameForAnonDecl();
if (!typedef_decl || !typedef_decl->getDeclName().isIdentifier()) {
return "";
}
// Only disambiguate user-defined types.
if (tag->getASTContext().getSourceManager().isInSystemHeader(
tag->getLocation())) {
return "";
}
return typedef_decl->getName().str() + '_' + tag->getKindName().str();
}

static std::unordered_map<std::string, size_t> type_mapping;

static size_t GetDeclId(const clang::NamedDecl *decl, bool internal) {
Expand Down
2 changes: 2 additions & 0 deletions cpp2rust/converter/converter_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ std::string GetID(const clang::Decl *decl);

std::string GetNamedDeclAsString(const clang::NamedDecl *decl);

std::string DisambiguateAnonymousTag(const clang::TagDecl *tag);

const char *AccessSpecifierAsString(clang::AccessSpecifier spec);

template <class T> llvm::SmallString<16> GetNumAsString(const T &num) {
Expand Down
20 changes: 16 additions & 4 deletions cpp2rust/converter/mapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,11 @@ std::string ToString(clang::QualType qual_type) {
return ToString(clang::cast<clang::NamedDecl>(tag));
}

if (auto renamed = DisambiguateAnonymousTag(qual_type->getAsTagDecl());
!renamed.empty()) {
return renamed;
}

std::string type;
llvm::raw_string_ostream os(type);
normalizeQualType(qual_type).print(os, getPrintPolicy());
Expand All @@ -745,16 +750,23 @@ std::string ToString(clang::QualType qual_type) {
std::string ToString(const clang::NamedDecl *decl) {
if (auto *record = clang::dyn_cast<clang::RecordDecl>(decl);
record && !record->getIdentifier()) {
if (auto renamed = DisambiguateAnonymousTag(record); !renamed.empty()) {
return renamed;
}
if (auto *typedef_decl = record->getTypedefNameForAnonDecl()) {
return ToString(clang::cast<clang::NamedDecl>(typedef_decl));
}
return GetNamedDeclAsString(record);
}

if (auto *enum_decl = clang::dyn_cast<clang::EnumDecl>(decl);
enum_decl && !enum_decl->getIdentifier() &&
!enum_decl->getTypedefNameForAnonDecl()) {
return std::format("anon_enum_{}", GetLineNumber(enum_decl));
if (auto *enum_decl = clang::dyn_cast<clang::EnumDecl>(decl)) {
if (auto renamed = DisambiguateAnonymousTag(enum_decl); !renamed.empty()) {
return renamed;
}
if (!enum_decl->getIdentifier() &&
!enum_decl->getTypedefNameForAnonDecl()) {
return std::format("anon_enum_{}", GetLineNumber(enum_decl));
}
}

std::string out;
Expand Down
3 changes: 3 additions & 0 deletions tests/multi-file/cross_tu_tag_collision/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 3.16)
project(cross_tu_tag_collision LANGUAGES C)
add_executable(app a.c b.c)
19 changes: 19 additions & 0 deletions tests/multi-file/cross_tu_tag_collision/a.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include <assert.h>

struct widget {
int id;
};

int b_value(void);

int a_value(void) {
struct widget w;
w.id = 11;
return w.id;
}

int main(void) {
assert(a_value() == 11);
assert(b_value() == 2);
return 0;
}
6 changes: 6 additions & 0 deletions tests/multi-file/cross_tu_tag_collision/b.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
typedef enum { WIDGET_A, WIDGET_B, WIDGET_C } widget;

int b_value(void) {
widget w = WIDGET_C;
return (int)w;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
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(Default)]
pub struct widget {
pub id: Value<i32>,
}
impl ByteRepr for widget {
fn to_bytes(&self, buf: &mut [u8]) {
(*self.id.borrow()).to_bytes(&mut buf[0..4]);
}
fn from_bytes(buf: &[u8]) -> Self {
Self {
id: Rc::new(RefCell::new(<i32>::from_bytes(&buf[0..4]))),
}
}
}
pub fn a_value_0() -> i32 {
let w: Value<widget> = <Value<widget>>::default();
(*(*w.borrow()).id.borrow_mut()) = 11;
return (*(*w.borrow()).id.borrow());
}
pub fn main() {
std::process::exit(main_0());
}
fn main_0() -> i32 {
assert!((((({ a_value_0() }) == 11) as i32) != 0));
assert!((((({ b_value_1() }) == 2) as i32) != 0));
return 0;
}
#[derive(Clone, Copy, PartialEq, Debug, Default)]
enum widget_enum {
#[default]
WIDGET_A = 0,
WIDGET_B = 1,
WIDGET_C = 2,
}
impl From<i32> for widget_enum {
fn from(n: i32) -> widget_enum {
match n {
0 => widget_enum::WIDGET_A,
1 => widget_enum::WIDGET_B,
2 => widget_enum::WIDGET_C,
_ => panic!("invalid widget_enum value: {}", n),
}
}
}
libcc2rs::impl_enum_inc_dec!(widget_enum);
pub fn b_value_1() -> i32 {
let w: Value<widget_enum> = Rc::new(RefCell::new(widget_enum::WIDGET_C));
return ((*w.borrow()) as i32).clone();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
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;
#[repr(C)]
#[derive(Copy, Clone, Default)]
pub struct widget {
pub id: i32,
}
pub unsafe fn a_value_0() -> i32 {
let mut w: widget = <widget>::default();
w.id = 11;
return w.id;
}
pub fn main() {
unsafe {
std::process::exit(main_0() as i32);
}
}
unsafe fn main_0() -> i32 {
assert!(((((unsafe { a_value_0() }) == (11)) as i32) != 0));
assert!(((((unsafe { b_value_1() }) == (2)) as i32) != 0));
return 0;
}
#[derive(Clone, Copy, PartialEq, Debug, Default)]
enum widget_enum {
#[default]
WIDGET_A = 0,
WIDGET_B = 1,
WIDGET_C = 2,
}
impl From<i32> for widget_enum {
fn from(n: i32) -> widget_enum {
match n {
0 => widget_enum::WIDGET_A,
1 => widget_enum::WIDGET_B,
2 => widget_enum::WIDGET_C,
_ => panic!("invalid widget_enum value: {}", n),
}
}
}
libcc2rs::impl_enum_inc_dec!(widget_enum);
pub unsafe fn b_value_1() -> i32 {
let mut w: widget_enum = widget_enum::WIDGET_C;
return (w as i32);
}
22 changes: 11 additions & 11 deletions tests/unit/out/refcount/anonymous_enum_c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,21 @@ impl ByteRepr for S {
}
}
#[derive(Clone, Copy, PartialEq, Debug, Default)]
enum TdEnum {
enum TdEnum_enum {
#[default]
TD_A = 0,
TD_B = 1,
}
impl From<i32> for TdEnum {
fn from(n: i32) -> TdEnum {
impl From<i32> for TdEnum_enum {
fn from(n: i32) -> TdEnum_enum {
match n {
0 => TdEnum::TD_A,
1 => TdEnum::TD_B,
_ => panic!("invalid TdEnum value: {}", n),
0 => TdEnum_enum::TD_A,
1 => TdEnum_enum::TD_B,
_ => panic!("invalid TdEnum_enum value: {}", n),
}
}
}
libcc2rs::impl_enum_inc_dec!(TdEnum);
libcc2rs::impl_enum_inc_dec!(TdEnum_enum);
#[derive(Clone, Copy, PartialEq, Debug, Default)]
enum anon_enum_24 {
#[default]
Expand Down Expand Up @@ -113,10 +113,10 @@ fn main_0() -> i32 {
assert!(((((anon_enum_3::FIRST_A as i32) != (anon_enum_3::FIRST_B as i32)) as i32) != 0));
assert!(((((anon_enum_11::SECOND_A as i32) != (anon_enum_11::SECOND_B as i32)) as i32) != 0));
assert!(((((anon_enum_31::THIRD_A as i32) != (anon_enum_31::THIRD_B as i32)) as i32) != 0));
let td: Value<TdEnum> = Rc::new(RefCell::new(TdEnum::TD_A));
assert!((((((*td.borrow()) as u32) == ((TdEnum::TD_A as i32) as u32)) as i32) != 0));
(*td.borrow_mut()) = TdEnum::TD_B;
assert!((((((*td.borrow()) as u32) == ((TdEnum::TD_B as i32) as u32)) as i32) != 0));
let td: Value<TdEnum_enum> = Rc::new(RefCell::new(TdEnum_enum::TD_A));
assert!((((((*td.borrow()) as u32) == ((TdEnum_enum::TD_A as i32) as u32)) as i32) != 0));
(*td.borrow_mut()) = TdEnum_enum::TD_B;
assert!((((((*td.borrow()) as u32) == ((TdEnum_enum::TD_B as i32) as u32)) as i32) != 0));
let w: Value<WithAnonField> = <Value<WithAnonField>>::default();
(*(*w.borrow()).field.borrow_mut()) = anon_enum_24::FIELD_A;
assert!(
Expand Down
32 changes: 16 additions & 16 deletions tests/unit/out/refcount/enum_int_interop_c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,23 @@ impl From<i32> for Option {
}
libcc2rs::impl_enum_inc_dec!(Option);
#[derive(Clone, Copy, PartialEq, Debug, Default)]
enum Tag {
enum Tag_enum {
#[default]
TAG_ZERO = 0,
TAG_ONE = 1,
TAG_TWO = 2,
}
impl From<i32> for Tag {
fn from(n: i32) -> Tag {
impl From<i32> for Tag_enum {
fn from(n: i32) -> Tag_enum {
match n {
0 => Tag::TAG_ZERO,
1 => Tag::TAG_ONE,
2 => Tag::TAG_TWO,
_ => panic!("invalid Tag value: {}", n),
0 => Tag_enum::TAG_ZERO,
1 => Tag_enum::TAG_ONE,
2 => Tag_enum::TAG_TWO,
_ => panic!("invalid Tag_enum value: {}", n),
}
}
}
libcc2rs::impl_enum_inc_dec!(Tag);
libcc2rs::impl_enum_inc_dec!(Tag_enum);
#[derive(Default)]
pub struct Entry {
pub name: Value<Ptr<u8>>,
Expand All @@ -76,7 +76,7 @@ thread_local!(
pub static global_opt_1: Value<Option> = Rc::new(RefCell::new(Option::OPT_B));
);
thread_local!(
pub static global_tag_2: Value<Tag> = Rc::new(RefCell::new(Tag::TAG_TWO));
pub static global_tag_2: Value<Tag_enum> = Rc::new(RefCell::new(Tag_enum::TAG_TWO));
);
thread_local!(
pub static entries_3: Value<Box<[Entry]>> = Rc::new(RefCell::new(Box::new([
Expand Down Expand Up @@ -199,17 +199,17 @@ fn main_0() -> i32 {
classify_option_5(_option)
});
assert!(((((*rc.borrow()) == 3) as i32) != 0));
let t: Value<Tag> = Rc::new(RefCell::new(Tag::TAG_ONE));
let t: Value<Tag_enum> = Rc::new(RefCell::new(Tag_enum::TAG_ONE));
assert!((((((*t.borrow()) as u32) == 1_u32) as i32) != 0));
assert!((((((*t.borrow()) as u32) == ((Tag::TAG_ONE as i32) as u32)) as i32) != 0));
assert!((((((*t.borrow()) as u32) == ((Tag_enum::TAG_ONE as i32) as u32)) as i32) != 0));
let ti: Value<i32> = Rc::new(RefCell::new(((*t.borrow()) as i32).clone()));
assert!(((((*ti.borrow()) == 1) as i32) != 0));
(*t.borrow_mut()) = Tag::from(2);
assert!((((((*t.borrow()) as u32) == ((Tag::TAG_TWO as i32) as u32)) as i32) != 0));
(*t.borrow_mut()) = Tag_enum::from(2);
assert!((((((*t.borrow()) as u32) == ((Tag_enum::TAG_TWO as i32) as u32)) as i32) != 0));
'switch: {
let __match_cond = ((*t.borrow()) as u32);
match __match_cond {
v if v == ((Tag::TAG_ZERO as i32) as u32) => {
v if v == ((Tag_enum::TAG_ZERO as i32) as u32) => {
return 90;
}
v if v == (1 as u32) => {
Expand All @@ -236,8 +236,8 @@ fn main_0() -> i32 {
!= 0)
);
assert!(
(((((*global_tag_2.with(Value::clone).borrow()) as u32) == ((Tag::TAG_TWO as i32) as u32))
as i32)
(((((*global_tag_2.with(Value::clone).borrow()) as u32)
== ((Tag_enum::TAG_TWO as i32) as u32)) as i32)
!= 0)
);
assert!(
Expand Down
22 changes: 11 additions & 11 deletions tests/unit/out/unsafe/anonymous_enum_c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,21 @@ pub struct S {
pub a: i32,
}
#[derive(Clone, Copy, PartialEq, Debug, Default)]
enum TdEnum {
enum TdEnum_enum {
#[default]
TD_A = 0,
TD_B = 1,
}
impl From<i32> for TdEnum {
fn from(n: i32) -> TdEnum {
impl From<i32> for TdEnum_enum {
fn from(n: i32) -> TdEnum_enum {
match n {
0 => TdEnum::TD_A,
1 => TdEnum::TD_B,
_ => panic!("invalid TdEnum value: {}", n),
0 => TdEnum_enum::TD_A,
1 => TdEnum_enum::TD_B,
_ => panic!("invalid TdEnum_enum value: {}", n),
}
}
}
libcc2rs::impl_enum_inc_dec!(TdEnum);
libcc2rs::impl_enum_inc_dec!(TdEnum_enum);
#[derive(Clone, Copy, PartialEq, Debug, Default)]
enum anon_enum_24 {
#[default]
Expand Down Expand Up @@ -106,10 +106,10 @@ unsafe fn main_0() -> i32 {
assert!(((((anon_enum_3::FIRST_A as i32) != (anon_enum_3::FIRST_B as i32)) as i32) != 0));
assert!(((((anon_enum_11::SECOND_A as i32) != (anon_enum_11::SECOND_B as i32)) as i32) != 0));
assert!(((((anon_enum_31::THIRD_A as i32) != (anon_enum_31::THIRD_B as i32)) as i32) != 0));
let mut td: TdEnum = TdEnum::TD_A;
assert!(((((td as u32) == ((TdEnum::TD_A as i32) as u32)) as i32) != 0));
td = (TdEnum::TD_B).clone();
assert!(((((td as u32) == ((TdEnum::TD_B as i32) as u32)) as i32) != 0));
let mut td: TdEnum_enum = TdEnum_enum::TD_A;
assert!(((((td as u32) == ((TdEnum_enum::TD_A as i32) as u32)) as i32) != 0));
td = (TdEnum_enum::TD_B).clone();
assert!(((((td as u32) == ((TdEnum_enum::TD_B as i32) as u32)) as i32) != 0));
let mut w: WithAnonField = <WithAnonField>::default();
w.field = anon_enum_24::FIELD_A;
assert!(((((w.field as u32) == ((anon_enum_24::FIELD_A as i32) as u32)) as i32) != 0));
Expand Down
Loading
Loading