From 226c3dec1a5465db6b2aace88cfb9beb30eba7c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gouveia?= Date: Sun, 16 Aug 2026 19:49:14 +0000 Subject: [PATCH 1/3] Fix operator name collisions --- cpp2rust/converter/mapper.cpp | 27 ++++++++++++++++-- rules/bitset/src.cpp | 26 +++++++++++++++++ rules/bitset/tgt_unsafe.rs | 28 +++++++++++++++++++ rules/src/modules.rs | 2 ++ tests/unit/bitset.cpp | 17 ++++++++++++ tests/unit/out/refcount/bitset.rs | 46 +++++++++++++++++++++++++++++++ tests/unit/out/unsafe/bitset.rs | 26 +++++++++++++++++ 7 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 rules/bitset/src.cpp create mode 100644 rules/bitset/tgt_unsafe.rs create mode 100644 tests/unit/bitset.cpp create mode 100644 tests/unit/out/refcount/bitset.rs create mode 100644 tests/unit/out/unsafe/bitset.rs diff --git a/cpp2rust/converter/mapper.cpp b/cpp2rust/converter/mapper.cpp index 83ebc988..d1528861 100644 --- a/cpp2rust/converter/mapper.cpp +++ b/cpp2rust/converter/mapper.cpp @@ -4,6 +4,7 @@ #include "converter/mapper.h" #include +#include #include #include #include @@ -922,8 +923,30 @@ std::string ToString(const clang::NamedDecl *decl) { } os << ToString(func_decl->getReturnType()) << ' '; - if (const auto *method_decl = - llvm::dyn_cast(func_decl)) { + if (const auto op = func_decl->getOverloadedOperator(); + op >= clang::OverloadedOperatorKind::OO_LessLess && + op <= clang::OverloadedOperatorKind::OO_GreaterGreaterEqual) { + // ensure matchTemplate does not consider these operator names when matching + func_decl->getQualifier().print(os, getPrintPolicy()); + os << "operator "; + switch (op) { + case clang::OverloadedOperatorKind::OO_LessLess: + os << "shl"; + break; + case clang::OverloadedOperatorKind::OO_GreaterGreater: + os << "shr"; + break; + case clang::OverloadedOperatorKind::OO_LessLessEqual: + os << "shleq"; + break; + case clang::OverloadedOperatorKind::OO_GreaterGreaterEqual: + os << "shreq"; + break; + default: + std::unreachable(); + } + } else if (const auto *method_decl = + llvm::dyn_cast(func_decl)) { if (method_decl->getParent()->isLambda() && method_decl->getOverloadedOperator() == clang::OO_Call) { func_decl->printName(os, getPrintPolicy()); diff --git a/rules/bitset/src.cpp b/rules/bitset/src.cpp new file mode 100644 index 00000000..b1bb556e --- /dev/null +++ b/rules/bitset/src.cpp @@ -0,0 +1,26 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include + +template using t1 = std::bitset; + +template std::bitset f1() { return std::bitset(); } + +template std::bitset f2(unsigned long long a0) { + return std::bitset(a0); +} + +template +std::bitset f3(const std::bitset &a0, std::size_t a1) { + return a0.operator<<(a1); +} + +template +std::bitset f4(const std::bitset &a0, std::size_t a1) { + return a0.operator>>(a1); +} + +template unsigned long f5(const std::bitset &a0) { + return a0.to_ulong(); +} diff --git a/rules/bitset/tgt_unsafe.rs b/rules/bitset/tgt_unsafe.rs new file mode 100644 index 00000000..5cd6d0d3 --- /dev/null +++ b/rules/bitset/tgt_unsafe.rs @@ -0,0 +1,28 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +fn t1() -> Vec { + Vec::new() +} + +fn f1() -> Vec { + Vec::new() +} + +fn f2(a0: u64) -> Vec { + (0..u64::BITS).map(|i| (a0 >> i) & 1 == 1).collect() +} + +fn f3(a0: Vec, a1: usize) -> Vec { + let mut bits = vec![false; a1]; + bits.extend(a0.iter()); + bits +} + +fn f4(a0: Vec, a1: usize) -> Vec { + a0.iter().skip(a1).copied().collect() +} + +fn f5(a0: Vec) -> u64 { + a0.iter().rev().fold(0u64, |acc, &b| (acc << 1) | b as u64) +} diff --git a/rules/src/modules.rs b/rules/src/modules.rs index f4404a32..1e885c97 100644 --- a/rules/src/modules.rs +++ b/rules/src/modules.rs @@ -14,6 +14,8 @@ pub mod array_tgt_unsafe; pub mod assert_tgt_refcount; #[path = r#"../assert/tgt_unsafe.rs"#] pub mod assert_tgt_unsafe; +#[path = r#"../bitset/tgt_unsafe.rs"#] +pub mod bitset_tgt_unsafe; #[path = r#"../brotli/tgt_refcount.rs"#] pub mod brotli_tgt_refcount; #[path = r#"../brotli/tgt_unsafe.rs"#] diff --git a/tests/unit/bitset.cpp b/tests/unit/bitset.cpp new file mode 100644 index 00000000..dfdfb190 --- /dev/null +++ b/tests/unit/bitset.cpp @@ -0,0 +1,17 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include +#include + +int main() { + std::bitset<16> b1(5); + std::bitset<16> b2 = b1 << 2; + std::bitset<16> b3 = b2 >> 1; + + assert(b1.to_ulong() == 5); + assert(b2.to_ulong() == 20); + assert(b3.to_ulong() == 10); + + return 0; +} diff --git a/tests/unit/out/refcount/bitset.rs b/tests/unit/out/refcount/bitset.rs new file mode 100644 index 00000000..ab0f44bf --- /dev/null +++ b/tests/unit/out/refcount/bitset.rs @@ -0,0 +1,46 @@ +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}; +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let b1: Value> = Rc::new(RefCell::new( + (0..u64::BITS).map(|i| (5_u64 >> i) & 1 == 1).collect(), + )); + let b2: Value> = Rc::new(RefCell::new({ + let mut bits = vec![false; 2_usize]; + bits.extend((*b1.borrow()).iter()); + bits + })); + let b3: Value> = Rc::new(RefCell::new( + (*b2.borrow()).iter().skip(1_usize).copied().collect(), + )); + assert!( + ((*b1.borrow()) + .iter() + .rev() + .fold(0u64, |acc, &b| (acc << 1) | b as u64) + == 5_u64) + ); + assert!( + ((*b2.borrow()) + .iter() + .rev() + .fold(0u64, |acc, &b| (acc << 1) | b as u64) + == 20_u64) + ); + assert!( + ((*b3.borrow()) + .iter() + .rev() + .fold(0u64, |acc, &b| (acc << 1) | b as u64) + == 10_u64) + ); + return 0; +} diff --git a/tests/unit/out/unsafe/bitset.rs b/tests/unit/out/unsafe/bitset.rs new file mode 100644 index 00000000..10ef0674 --- /dev/null +++ b/tests/unit/out/unsafe/bitset.rs @@ -0,0 +1,26 @@ +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; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut b1: Vec = (0..u64::BITS).map(|i| (5_u64 >> i) & 1 == 1).collect(); + let mut b2: Vec = { + let mut bits = vec![false; 2_usize]; + bits.extend(b1.iter()); + bits + }; + let mut b3: Vec = b2.iter().skip(1_usize).copied().collect(); + assert!(((b1.iter().rev().fold(0u64, |acc, &b| (acc << 1) | b as u64)) == (5_u64))); + assert!(((b2.iter().rev().fold(0u64, |acc, &b| (acc << 1) | b as u64)) == (20_u64))); + assert!(((b3.iter().rev().fold(0u64, |acc, &b| (acc << 1) | b as u64)) == (10_u64))); + return 0; +} From a26f621696fbcb159f9f1740c17d2789bd144ce0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gouveia?= Date: Sun, 16 Aug 2026 20:14:58 +0000 Subject: [PATCH 2/3] Address reviews --- cpp2rust/converter/mapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp2rust/converter/mapper.cpp b/cpp2rust/converter/mapper.cpp index d1528861..845cf3ad 100644 --- a/cpp2rust/converter/mapper.cpp +++ b/cpp2rust/converter/mapper.cpp @@ -943,7 +943,7 @@ std::string ToString(const clang::NamedDecl *decl) { os << "shreq"; break; default: - std::unreachable(); + assert(0 && "Unexpected overloaded operator kind"); } } else if (const auto *method_decl = llvm::dyn_cast(func_decl)) { From 533a76ebdeb0fe32f5f5b9459ce4e1f626feb86a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gouveia?= Date: Sun, 16 Aug 2026 20:28:46 +0000 Subject: [PATCH 3/3] Use std::byte to test the patch --- rules/bitset/src.cpp | 26 ----------------- rules/bitset/tgt_unsafe.rs | 28 ------------------- rules/cstddef/src.cpp | 14 ++++++++++ rules/cstddef/tgt_unsafe.rs | 26 +++++++++++++++++ rules/src/modules.rs | 4 +-- tests/unit/bitset.cpp | 17 ------------ tests/unit/byte.cpp | 26 +++++++++++++++++ tests/unit/out/refcount/bitset.rs | 46 ------------------------------- tests/unit/out/refcount/byte.rs | 35 +++++++++++++++++++++++ tests/unit/out/unsafe/bitset.rs | 26 ----------------- tests/unit/out/unsafe/byte.rs | 37 +++++++++++++++++++++++++ 11 files changed, 140 insertions(+), 145 deletions(-) delete mode 100644 rules/bitset/src.cpp delete mode 100644 rules/bitset/tgt_unsafe.rs create mode 100644 rules/cstddef/src.cpp create mode 100644 rules/cstddef/tgt_unsafe.rs delete mode 100644 tests/unit/bitset.cpp create mode 100644 tests/unit/byte.cpp delete mode 100644 tests/unit/out/refcount/bitset.rs create mode 100644 tests/unit/out/refcount/byte.rs delete mode 100644 tests/unit/out/unsafe/bitset.rs create mode 100644 tests/unit/out/unsafe/byte.rs diff --git a/rules/bitset/src.cpp b/rules/bitset/src.cpp deleted file mode 100644 index b1bb556e..00000000 --- a/rules/bitset/src.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2022-present INESC-ID. -// Distributed under the MIT license that can be found in the LICENSE file. - -#include - -template using t1 = std::bitset; - -template std::bitset f1() { return std::bitset(); } - -template std::bitset f2(unsigned long long a0) { - return std::bitset(a0); -} - -template -std::bitset f3(const std::bitset &a0, std::size_t a1) { - return a0.operator<<(a1); -} - -template -std::bitset f4(const std::bitset &a0, std::size_t a1) { - return a0.operator>>(a1); -} - -template unsigned long f5(const std::bitset &a0) { - return a0.to_ulong(); -} diff --git a/rules/bitset/tgt_unsafe.rs b/rules/bitset/tgt_unsafe.rs deleted file mode 100644 index 5cd6d0d3..00000000 --- a/rules/bitset/tgt_unsafe.rs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2022-present INESC-ID. -// Distributed under the MIT license that can be found in the LICENSE file. - -fn t1() -> Vec { - Vec::new() -} - -fn f1() -> Vec { - Vec::new() -} - -fn f2(a0: u64) -> Vec { - (0..u64::BITS).map(|i| (a0 >> i) & 1 == 1).collect() -} - -fn f3(a0: Vec, a1: usize) -> Vec { - let mut bits = vec![false; a1]; - bits.extend(a0.iter()); - bits -} - -fn f4(a0: Vec, a1: usize) -> Vec { - a0.iter().skip(a1).copied().collect() -} - -fn f5(a0: Vec) -> u64 { - a0.iter().rev().fold(0u64, |acc, &b| (acc << 1) | b as u64) -} diff --git a/rules/cstddef/src.cpp b/rules/cstddef/src.cpp new file mode 100644 index 00000000..9ae81ccd --- /dev/null +++ b/rules/cstddef/src.cpp @@ -0,0 +1,14 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include + +using t1 = std::byte; + +std::byte f1(const std::byte &a0, unsigned a1) { return operator<<(a0, a1); } + +std::byte f2(const std::byte &a0, unsigned a1) { return operator>>(a0, a1); } + +std::byte f3(std::byte &a0, unsigned a1) { return operator<<=(a0, a1); } + +std::byte f4(std::byte &a0, unsigned a1) { return operator>>=(a0, a1); } diff --git a/rules/cstddef/tgt_unsafe.rs b/rules/cstddef/tgt_unsafe.rs new file mode 100644 index 00000000..d40e1d1c --- /dev/null +++ b/rules/cstddef/tgt_unsafe.rs @@ -0,0 +1,26 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +fn t1() -> u8 { + Default::default() +} + +fn f1(a0: &mut u8, a1: u32) -> u8 { + *a0 << a1 +} + +fn f2(a0: &mut u8, a1: u32) -> u8 { + *a0 >> a1 +} + +fn f3(a0: &mut u8, a1: u32) -> u8 { + let n_ = *a0 << a1; + *a0 = n_; + *a0 +} + +fn f4(a0: &mut u8, a1: u32) -> u8 { + let n_ = *a0 >> a1; + *a0 = n_; + *a0 +} diff --git a/rules/src/modules.rs b/rules/src/modules.rs index 1e885c97..efedce2b 100644 --- a/rules/src/modules.rs +++ b/rules/src/modules.rs @@ -14,8 +14,6 @@ pub mod array_tgt_unsafe; pub mod assert_tgt_refcount; #[path = r#"../assert/tgt_unsafe.rs"#] pub mod assert_tgt_unsafe; -#[path = r#"../bitset/tgt_unsafe.rs"#] -pub mod bitset_tgt_unsafe; #[path = r#"../brotli/tgt_refcount.rs"#] pub mod brotli_tgt_refcount; #[path = r#"../brotli/tgt_unsafe.rs"#] @@ -30,6 +28,8 @@ pub mod carray_tgt_refcount; pub mod carray_tgt_unsafe; #[path = r#"../cmath/tgt_unsafe.rs"#] pub mod cmath_tgt_unsafe; +#[path = r#"../cstddef/tgt_unsafe.rs"#] +pub mod cstddef_tgt_unsafe; #[path = r#"../cstdlib/tgt_refcount.rs"#] pub mod cstdlib_tgt_refcount; #[path = r#"../cstdlib/tgt_unsafe.rs"#] diff --git a/tests/unit/bitset.cpp b/tests/unit/bitset.cpp deleted file mode 100644 index dfdfb190..00000000 --- a/tests/unit/bitset.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2022-present INESC-ID. -// Distributed under the MIT license that can be found in the LICENSE file. - -#include -#include - -int main() { - std::bitset<16> b1(5); - std::bitset<16> b2 = b1 << 2; - std::bitset<16> b3 = b2 >> 1; - - assert(b1.to_ulong() == 5); - assert(b2.to_ulong() == 20); - assert(b3.to_ulong() == 10); - - return 0; -} diff --git a/tests/unit/byte.cpp b/tests/unit/byte.cpp new file mode 100644 index 00000000..9eead968 --- /dev/null +++ b/tests/unit/byte.cpp @@ -0,0 +1,26 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +#include +#include + +int main() { + std::byte b1{0x01}; + + unsigned ushift1 = 3; + std::byte shl1 = b1 << ushift1; + assert(shl1 == std::byte(0x08)); + + unsigned ushift2 = 2; + std::byte shr1 = shl1 >> ushift2; + assert(shr1 == std::byte(0x02)); + + unsigned ushift3 = 5; + b1 <<= ushift3; + assert(b1 == std::byte(0x20)); + + unsigned ushift4 = 3; + b1 >>= ushift4; + assert(b1 == std::byte(0x04)); + return 0; +} diff --git a/tests/unit/out/refcount/bitset.rs b/tests/unit/out/refcount/bitset.rs deleted file mode 100644 index ab0f44bf..00000000 --- a/tests/unit/out/refcount/bitset.rs +++ /dev/null @@ -1,46 +0,0 @@ -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}; -pub fn main() { - std::process::exit(main_0()); -} -fn main_0() -> i32 { - let b1: Value> = Rc::new(RefCell::new( - (0..u64::BITS).map(|i| (5_u64 >> i) & 1 == 1).collect(), - )); - let b2: Value> = Rc::new(RefCell::new({ - let mut bits = vec![false; 2_usize]; - bits.extend((*b1.borrow()).iter()); - bits - })); - let b3: Value> = Rc::new(RefCell::new( - (*b2.borrow()).iter().skip(1_usize).copied().collect(), - )); - assert!( - ((*b1.borrow()) - .iter() - .rev() - .fold(0u64, |acc, &b| (acc << 1) | b as u64) - == 5_u64) - ); - assert!( - ((*b2.borrow()) - .iter() - .rev() - .fold(0u64, |acc, &b| (acc << 1) | b as u64) - == 20_u64) - ); - assert!( - ((*b3.borrow()) - .iter() - .rev() - .fold(0u64, |acc, &b| (acc << 1) | b as u64) - == 10_u64) - ); - return 0; -} diff --git a/tests/unit/out/refcount/byte.rs b/tests/unit/out/refcount/byte.rs new file mode 100644 index 00000000..c7b6fbfa --- /dev/null +++ b/tests/unit/out/refcount/byte.rs @@ -0,0 +1,35 @@ +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}; +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let b1: Value = Rc::new(RefCell::new(1_u8)); + let ushift1: Value = Rc::new(RefCell::new(3_u32)); + let shl1: Value = Rc::new(RefCell::new((*b1.borrow()) << (*ushift1.borrow()))); + assert!(((*shl1.borrow()) == 8)); + let ushift2: Value = Rc::new(RefCell::new(2_u32)); + let shr1: Value = Rc::new(RefCell::new((*shl1.borrow()) >> (*ushift2.borrow()))); + assert!(((*shr1.borrow()) == 2)); + let ushift3: Value = Rc::new(RefCell::new(5_u32)); + { + let n_ = (*b1.borrow()) << (*ushift3.borrow()); + (*b1.borrow_mut()) = n_; + (*b1.borrow()) + }; + assert!(((*b1.borrow()) == 32)); + let ushift4: Value = Rc::new(RefCell::new(3_u32)); + { + let n_ = (*b1.borrow()) >> (*ushift4.borrow()); + (*b1.borrow_mut()) = n_; + (*b1.borrow()) + }; + assert!(((*b1.borrow()) == 4)); + return 0; +} diff --git a/tests/unit/out/unsafe/bitset.rs b/tests/unit/out/unsafe/bitset.rs deleted file mode 100644 index 10ef0674..00000000 --- a/tests/unit/out/unsafe/bitset.rs +++ /dev/null @@ -1,26 +0,0 @@ -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; -pub fn main() { - unsafe { - std::process::exit(main_0() as i32); - } -} -unsafe fn main_0() -> i32 { - let mut b1: Vec = (0..u64::BITS).map(|i| (5_u64 >> i) & 1 == 1).collect(); - let mut b2: Vec = { - let mut bits = vec![false; 2_usize]; - bits.extend(b1.iter()); - bits - }; - let mut b3: Vec = b2.iter().skip(1_usize).copied().collect(); - assert!(((b1.iter().rev().fold(0u64, |acc, &b| (acc << 1) | b as u64)) == (5_u64))); - assert!(((b2.iter().rev().fold(0u64, |acc, &b| (acc << 1) | b as u64)) == (20_u64))); - assert!(((b3.iter().rev().fold(0u64, |acc, &b| (acc << 1) | b as u64)) == (10_u64))); - return 0; -} diff --git a/tests/unit/out/unsafe/byte.rs b/tests/unit/out/unsafe/byte.rs new file mode 100644 index 00000000..a48cf14c --- /dev/null +++ b/tests/unit/out/unsafe/byte.rs @@ -0,0 +1,37 @@ +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; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut b1: u8 = 1_u8; + let mut ushift1: u32 = 3_u32; + let mut shl1: u8 = b1 << ushift1; + assert!(((shl1) == (8))); + let mut ushift2: u32 = 2_u32; + let mut shr1: u8 = shl1 >> ushift2; + assert!(((shr1) == (2))); + let mut ushift3: u32 = 5_u32; + { + let n_ = b1 << ushift3; + b1 = n_; + b1 + }; + assert!(((b1) == (32))); + let mut ushift4: u32 = 3_u32; + { + let n_ = b1 >> ushift4; + b1 = n_; + b1 + }; + assert!(((b1) == (4))); + return 0; +}