From a1eee41155b296d15d137f74cb7582c1aa8e0c0d Mon Sep 17 00:00:00 2001 From: Siddhi sahu Date: Thu, 22 Oct 2026 13:42:49 +0530 Subject: [PATCH 1/8] Add std::stack overload test with default constructor Signed-off-by: Siddhi sahu --- cpp-overload-test/src/lib.rs | 1 + cpp-overload-test/src/stdcpp/stack.rs | 63 +++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 cpp-overload-test/src/stdcpp/stack.rs diff --git a/cpp-overload-test/src/lib.rs b/cpp-overload-test/src/lib.rs index b72552c..e9f9886 100644 --- a/cpp-overload-test/src/lib.rs +++ b/cpp-overload-test/src/lib.rs @@ -8,4 +8,5 @@ pub mod stdcpp { // Add new modules for each type here, in alphabetical order. pub mod forward_list; + pub mod stack; } diff --git a/cpp-overload-test/src/stdcpp/stack.rs b/cpp-overload-test/src/stdcpp/stack.rs new file mode 100644 index 0000000..6448601 --- /dev/null +++ b/cpp-overload-test/src/stdcpp/stack.rs @@ -0,0 +1,63 @@ +//! Test that C++ overloads for [std::stack][stack] can be successfully represented in Rust. +//! +//! [stack]: https://en.cppreference.com/cpp/container/stack + +#![allow(unused_braces, reason = "Generated by overload! macro")] + +use cpp::cpp; +use splat_overload::overload; +use std::ffi::{c_char, c_void}; +use std::marker::PhantomData; + +// C++ header includes +cpp! {{ + #include +}} + +pub type T = std::ffi::c_int; + +#[cfg_attr(not(test), expect(dead_code, reason = "only used in tests"))] +//A wrapper struct named StdStack that holds the returned c++ pointer. +pub struct StdStack(*mut c_void, PhantomData); + +#[cfg_attr(not(test), expect(dead_code, reason = "only used in tests"))] +#[allow( + non_upper_case_globals, + reason = "Triggered by cpp! macro in rust-analyzer" +)] +impl StdStack { + fn default() -> StdStack { + let stack = unsafe { + cpp!([] -> *mut c_void as "std::stack*"{ + return new std::stack(); + }) + }; + StdStack(stack, PhantomData) + } + + fn is_empty(&self) -> bool { + let slf = self.0 as *const c_void; + let empty = unsafe { + cpp!([slf as "const std::stack*"] -> c_char as "char" { + // char is FFI safe, but rust bool is not + return slf->empty(); + }) + }; + empty != 0 + } +} + +overload! { + impl StdStack { + // an empty stack + pub fn new() -> StdStack { + StdStack::default() + } + } +} + +#[test] +pub fn test_stack() { + let default_stack = StdStack::new(); + assert!(default_stack.is_empty()); +} From cb9f1bd660d105e0b2f6147c360d82276abdb54d Mon Sep 17 00:00:00 2001 From: Siddhi sahu Date: Fri, 23 Oct 2026 18:22:19 +0530 Subject: [PATCH 2/8] Add push, size, top_const helpers (non overloading) Signed-off-by: Siddhi sahu --- cpp-overload-test/src/stdcpp/stack.rs | 51 +++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/cpp-overload-test/src/stdcpp/stack.rs b/cpp-overload-test/src/stdcpp/stack.rs index 6448601..94262f2 100644 --- a/cpp-overload-test/src/stdcpp/stack.rs +++ b/cpp-overload-test/src/stdcpp/stack.rs @@ -6,18 +6,19 @@ use cpp::cpp; use splat_overload::overload; -use std::ffi::{c_char, c_void}; +use std::ffi::{c_char, c_size_t, c_void}; use std::marker::PhantomData; // C++ header includes cpp! {{ #include + #include }} pub type T = std::ffi::c_int; +/// A wrapper struct named StdStack that holds the returned c++ pointer. #[cfg_attr(not(test), expect(dead_code, reason = "only used in tests"))] -//A wrapper struct named StdStack that holds the returned c++ pointer. pub struct StdStack(*mut c_void, PhantomData); #[cfg_attr(not(test), expect(dead_code, reason = "only used in tests"))] @@ -45,6 +46,40 @@ impl StdStack { }; empty != 0 } + + fn push(&mut self, value: T) { + let slf: *mut c_void = self.0; + unsafe { + cpp!([slf as "std::stack*", value as "int"]{ + slf->push(value); + }) + } + } + + fn size(&self) -> c_size_t { + let slf = self.0 as *const c_void; + + unsafe { + cpp!([slf as "const std::stack*"] -> c_size_t as "size_t"{ + return slf->size(); + }) + } + } + + fn top_const(&self) -> Option<&T> { + let slf = self.0 as *const c_void; + + unsafe { + cpp!([slf as "const std::stack*"] -> Option<&T> as "const int*"{ + //calling top() on an empty stack is undefined behaviour in cpp + if(slf->empty()){ + return nullptr; + }else{ + return &slf->top(); + } + }) + } + } } overload! { @@ -60,4 +95,16 @@ overload! { pub fn test_stack() { let default_stack = StdStack::new(); assert!(default_stack.is_empty()); + + //push, size, top_const + + let mut stack = StdStack::new(); + assert_eq!(stack.size(), 0); + assert_eq!(stack.top_const(), None); + + stack.push(10); + stack.push(20); + assert!(!stack.is_empty()); + assert_eq!(stack.size(), 2); + assert_eq!(stack.top_const(), Some(&20)); } From 7a3fa385275e56bfccb29aa2d66a197efba63a45 Mon Sep 17 00:00:00 2001 From: Siddhi sahu Date: Sun, 25 Oct 2026 18:47:25 +0530 Subject: [PATCH 3/8] add copy and move constructors overloads Signed-off-by: Siddhi sahu --- cpp-overload-test/src/stdcpp/stack.rs | 60 ++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/cpp-overload-test/src/stdcpp/stack.rs b/cpp-overload-test/src/stdcpp/stack.rs index 94262f2..99ebf7e 100644 --- a/cpp-overload-test/src/stdcpp/stack.rs +++ b/cpp-overload-test/src/stdcpp/stack.rs @@ -13,6 +13,7 @@ use std::marker::PhantomData; cpp! {{ #include #include + #include }} pub type T = std::ffi::c_int; @@ -80,24 +81,55 @@ impl StdStack { }) } } + + fn copy_from(other: &StdStack) -> StdStack { + let other = other.0 as *const c_void; + let stack = unsafe { + cpp!([other as "const std::stack*"] -> *mut c_void as "std::stack*" { + const std::stack other_ = *other; + return new std::stack(other_); + }) + }; + StdStack(stack, PhantomData) + } + + fn move_from(other: &mut StdStack) -> StdStack { + let other = other.0; + let stack = unsafe { + cpp!([other as "std::stack*"] -> *mut c_void as "std::stack*" { + std::stack other_ = std::move(*other); + return new std::stack(other_); + }) + }; + StdStack(stack, PhantomData) + } } overload! { impl StdStack { - // an empty stack + /// an empty stack pub fn new() -> StdStack { StdStack::default() } + /// Clone stack items into a new stack from a shared stack reference + pub fn new(other: &StdStack) -> StdStack { + StdStack::copy_from(other) + } + + /// Move stack items into a new stack from a mutable stack reference. + pub fn new(other: &mut StdStack) -> StdStack { + StdStack::move_from(other) + } } } +/// These tests show that the correct Rust and C++ overloads are being called. #[test] pub fn test_stack() { let default_stack = StdStack::new(); assert!(default_stack.is_empty()); //push, size, top_const - let mut stack = StdStack::new(); assert_eq!(stack.size(), 0); assert_eq!(stack.top_const(), None); @@ -107,4 +139,28 @@ pub fn test_stack() { assert!(!stack.is_empty()); assert_eq!(stack.size(), 2); assert_eq!(stack.top_const(), Some(&20)); + + //copy constructor + let mut original = StdStack::new(); + original.push(13); + original.push(09); + + let copy = StdStack::new(&original); + assert_eq!(copy.size(), 2); + assert_eq!(copy.top_const(), Some(&09)); + + //changing original will not change copy, because copy is independent + original.push(10); + assert_eq!(copy.size(), 2); + assert_eq!(original.size(), 3); + + // move constructor + let mut real = StdStack::new(); + real.push(10); + real.push(20); + real.push(30); + + let moved_stack = StdStack::new(&mut real); + assert_eq!(moved_stack.size(), 3); + assert_eq!(moved_stack.top_const(), Some(&30)); } From dace66be99332b642ec2d8ab777a2d64d12aebba Mon Sep 17 00:00:00 2001 From: Siddhi sahu Date: Tue, 3 Nov 2026 18:39:24 +0530 Subject: [PATCH 4/8] Add slice, iterator constructors, make copy/move call constructors directly Signed-off-by: Siddhi sahu --- cpp-overload-test/src/lib.rs | 2 +- cpp-overload-test/src/stdcpp/stack.rs | 78 +++++++++++++++++++++++++-- 2 files changed, 74 insertions(+), 6 deletions(-) diff --git a/cpp-overload-test/src/lib.rs b/cpp-overload-test/src/lib.rs index 82f7613..b81036a 100644 --- a/cpp-overload-test/src/lib.rs +++ b/cpp-overload-test/src/lib.rs @@ -10,8 +10,8 @@ pub mod stdcpp { // Add new modules for each type here, in alphabetical order. pub mod forward_list; - pub mod stack; pub mod hash; + pub mod stack; pub mod unordered_multiset; } diff --git a/cpp-overload-test/src/stdcpp/stack.rs b/cpp-overload-test/src/stdcpp/stack.rs index 99ebf7e..da46bb6 100644 --- a/cpp-overload-test/src/stdcpp/stack.rs +++ b/cpp-overload-test/src/stdcpp/stack.rs @@ -1,5 +1,6 @@ //! Test that C++ overloads for [std::stack][stack] can be successfully represented in Rust. //! +//! `std::stack` is a container adapter: it wraps a container (`std::deque` by default ) //! [stack]: https://en.cppreference.com/cpp/container/stack #![allow(unused_braces, reason = "Generated by overload! macro")] @@ -86,8 +87,7 @@ impl StdStack { let other = other.0 as *const c_void; let stack = unsafe { cpp!([other as "const std::stack*"] -> *mut c_void as "std::stack*" { - const std::stack other_ = *other; - return new std::stack(other_); + return new std::stack(*other); }) }; StdStack(stack, PhantomData) @@ -97,8 +97,45 @@ impl StdStack { let other = other.0; let stack = unsafe { cpp!([other as "std::stack*"] -> *mut c_void as "std::stack*" { - std::stack other_ = std::move(*other); - return new std::stack(other_); + return new std::stack(std::move(*other)); + }) + }; + StdStack(stack, PhantomData) + } + + fn from_slice(items: &[T]) -> StdStack { + if items.is_empty() { + return StdStack::default(); + } + let len = items.len(); + + let items: *const T = items.as_ptr(); + let stack = unsafe { + cpp!([items as "const int*", len as "size_t"] -> *mut c_void as "std::stack*" { + return new std::stack(items, items + len); + }) + }; + StdStack(stack, PhantomData) + } + + fn from_iter(iter: &mut dyn Iterator) -> StdStack { + let items: Vec = iter.collect(); + // An empty Rust Vec is guaranteed to have a dangling pointer, see + // + if items.is_empty() { + return StdStack::default(); + } + let len = items.len(); + let items: *const T = items.as_ptr(); + // SAFETY: items is a non-null pointer to len properly initialized values of T + let stack = unsafe { + cpp!([items as "const int*", len as "size_t"] -> *mut c_void as "std::stack*"{ + std::vector vec = std::vector(items, items + len); + #ifdef __cpp_lib_containers_ranges + return new std::stack(std::from_range, vec); + #else + #error "std::from_range is not available, try using `-std=c++23` or a newer compiler" + #endif }) }; StdStack(stack, PhantomData) @@ -120,13 +157,22 @@ overload! { pub fn new(other: &mut StdStack) -> StdStack { StdStack::move_from(other) } + + /// constructs a stack by copying items from a slice. + pub fn new(items: &[T]) -> StdStack { + StdStack::from_slice(items) + } + + pub fn new(iter: &mut dyn Iterator) -> StdStack { + StdStack::from_iter(iter) + } } } /// These tests show that the correct Rust and C++ overloads are being called. #[test] pub fn test_stack() { - let default_stack = StdStack::new(); + let mut default_stack = StdStack::new(); assert!(default_stack.is_empty()); //push, size, top_const @@ -163,4 +209,26 @@ pub fn test_stack() { let moved_stack = StdStack::new(&mut real); assert_eq!(moved_stack.size(), 3); assert_eq!(moved_stack.top_const(), Some(&30)); + assert!(real.is_empty()); + assert_eq!(real.size(), 0); + assert_eq!(real.top_const(), None); + //moving an empty stack is fine too + let moved_empty = StdStack::new(&mut default_stack); + assert!(moved_empty.is_empty()); + + // ### Limitations: with overload!, caller has to call .as_slice(), because array reference doesnot convert into slice automatically. + // no mut since, from_slice is never changed. + let from_slice = StdStack::new([1, 2, 3].as_slice()); + assert_eq!(from_slice.size(), 3); + assert_eq!(from_slice.top_const(), Some(&3)); + let from_empty_slice = StdStack::new([].as_slice()); + assert!(from_empty_slice.is_empty()); + + let mut iter: std::array::IntoIter = [1, 2, 3].into_iter(); + let from_iter = StdStack::new(&mut iter as &mut dyn Iterator); + assert_eq!(from_iter.size(), 3); + assert_eq!(from_iter.top_const(), Some(&3)); + let mut empty_iter: std::array::IntoIter = [].into_iter(); + let from_empty_iter = StdStack::new(&mut empty_iter as &mut dyn Iterator); + assert!(from_empty_iter.is_empty()); } From cdd714e192b45cd6b592415563926f4ed185ceed Mon Sep 17 00:00:00 2001 From: Siddhi sahu Date: Tue, 3 Nov 2026 22:59:04 +0530 Subject: [PATCH 5/8] Add Limitations and Ergonomics --- cpp-overload-test/src/stdcpp/stack.rs | 42 +++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/cpp-overload-test/src/stdcpp/stack.rs b/cpp-overload-test/src/stdcpp/stack.rs index da46bb6..12b847c 100644 --- a/cpp-overload-test/src/stdcpp/stack.rs +++ b/cpp-overload-test/src/stdcpp/stack.rs @@ -7,6 +7,10 @@ use cpp::cpp; use splat_overload::overload; +// ### Limitations +// +// We want `c_bool` here, but rust only has `c_char` , so `is_empty` converts the +// `char` back to bool . use std::ffi::{c_char, c_size_t, c_void}; use std::marker::PhantomData; @@ -15,6 +19,8 @@ cpp! {{ #include #include #include + #include + #include }} pub type T = std::ffi::c_int; @@ -142,6 +148,15 @@ impl StdStack { } } +// Constructors: `new(...)` +// +// ### Limitations +// +// These contructors are not wrapped yet: +// - `stack(const Container&)` and `stack(Container&&)`: they take a cpp `std::deque`, +// so they need a rust wrapper for `deque` first, which is not done yet. +// - constructors that differ by allocator argument : ignored, because they are not interesting overloads +// to cover. overload! { impl StdStack { /// an empty stack @@ -149,11 +164,23 @@ overload! { StdStack::default() } /// Clone stack items into a new stack from a shared stack reference + /// + /// ### Ergonomics + /// + /// `new(&s)` copies and `new(&mut s)` moves, but at the call site they look almost + /// same and do very different things, + /// it will be very easy to mix them up. pub fn new(other: &StdStack) -> StdStack { StdStack::copy_from(other) } /// Move stack items into a new stack from a mutable stack reference. + /// + /// ### Limitations + /// + /// After a cpp move, the old stack still exists in a "valid but unspecified" state, + /// which is empty in practice. A Rust moves makes the old variable unusauable , + /// so idiomatic rust would take the stack by value instead of `&mut` pub fn new(other: &mut StdStack) -> StdStack { StdStack::move_from(other) } @@ -163,6 +190,21 @@ overload! { StdStack::from_slice(items) } + /// constructs a stack from an iterator + /// + /// ### Limitations + /// The caller has to cast the iterator, like `&mut iter as &mut dyn Iterator` + /// because rust doesnot automatically convert it to `dyn Iterator` automatically + /// + /// It used the dyn Iterator and not a generic `impl Iterator` because overload! + /// doesn't support generics in this position yet and a `impl Iterator` + /// could overlap with the `&[T]` overload. + /// + /// the items are basically copied twice, first into a Rust `Vec` and + /// then into a cpp `std::vector`. + /// its simple, but it do the extra work. + /// In c++, we need a `std::from_range` tag to tell this constructor apart from the others. + /// Rust doesnot need a tag because argu,ment types are already there. pub fn new(iter: &mut dyn Iterator) -> StdStack { StdStack::from_iter(iter) } From f0738f3bfe858555df6dfbc5d2b791cb647c8e16 Mon Sep 17 00:00:00 2001 From: Siddhi sahu Date: Fri, 6 Nov 2026 17:23:46 +0530 Subject: [PATCH 6/8] Add failing stack example and overloading analysis Signed-off-by: Siddhi sahu --- cpp-overload-test/examples/stdcpp-stack.rs | 52 +++++++++++++++++++ .../examples/stdcpp-stack.stderr | 14 +++++ cpp-overload-test/src/stdcpp/stack.rs | 9 ++-- cpp-overloads-in-rust.md | 3 ++ 4 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 cpp-overload-test/examples/stdcpp-stack.rs create mode 100644 cpp-overload-test/examples/stdcpp-stack.stderr diff --git a/cpp-overload-test/examples/stdcpp-stack.rs b/cpp-overload-test/examples/stdcpp-stack.rs new file mode 100644 index 0000000..d2d0dba --- /dev/null +++ b/cpp-overload-test/examples/stdcpp-stack.rs @@ -0,0 +1,52 @@ +//! Test C++ [std::stack][stack] overloads that can't be represented in Rust, and record the macro diagnostics. +//! Working overloads are in [stack.rs]. +//! +//! [stack]: https://en.cppreference.com/cpp/container/stack +//! [stack.rs]: https://github.com/rustfoundation/overloading-macros/blob/main/cpp-overload-test/src/stdcpp/stack.rs +//! +//! The `cpp!` macro doesn't work here. + +#![feature(splat, tuple_trait, c_size_t)] +#![allow(incomplete_features)] +#![allow(unused_braces)] + +use splat_overload::overload; +use std::ffi::c_void; +use std::marker::PhantomData; + +#[expect(dead_code, reason = "Incompatible overloads can't be used")] +struct StdStack(*mut c_void, PhantomData); + +type T = std::ffi::c_int; + +overload! { + impl StdStack { + /// ### Incompatibilities + /// + /// cpp has two `two` top functions with the same name, `T& top()` return an item you can change, + /// and `const T& top() const` return a read only one. they only differ by const, + /// which in Rust is `&mut self` reciever vs a `&self ` receiver. + /// + /// the overload! cant express this. it turns all overloads with the same name into one + /// real function, that sends each call to the right version. and one function can + /// only have one kind of receiver , never `&self` and `&mut self` at the same time. + /// + /// ### Workarounds + /// + /// The simplest fix would be to not overload at all and use the two names + /// `top()` for read only version and `top_mut()` for the changeable one. + /// Different names means theres no overloading is needed , so macro isn't + /// involved. It will not be same as C++, where both functions are + /// called top. But its how Rust normally does it, Vec has first() and first_mut() + /// ANd Rust users would find it natural. + fn top(&self) where T:Sized { + todo!() + } + + fn top(&mut self) where T: Sized { + todo!() + } + } +} + +pub fn main() {} diff --git a/cpp-overload-test/examples/stdcpp-stack.stderr b/cpp-overload-test/examples/stdcpp-stack.stderr new file mode 100644 index 0000000..d64b540 --- /dev/null +++ b/cpp-overload-test/examples/stdcpp-stack.stderr @@ -0,0 +1,14 @@ +error: proc macro panicked + --> cpp-overload-test/examples/stdcpp-stack.rs:22:1 + | +22 | / overload! { +23 | | impl StdStack { +24 | | /// ### Incompatibilities +25 | | /// +... | +50 | | } + | |_^ + | + = help: message: all overloads must have the same receiver kind (&self, &mut self, self, or no receiver), got top: &self and top: &mut self + +error: could not compile `cpp-overload-test` (example "stdcpp-stack") due to 1 previous error diff --git a/cpp-overload-test/src/stdcpp/stack.rs b/cpp-overload-test/src/stdcpp/stack.rs index 12b847c..a77fbbb 100644 --- a/cpp-overload-test/src/stdcpp/stack.rs +++ b/cpp-overload-test/src/stdcpp/stack.rs @@ -7,10 +7,6 @@ use cpp::cpp; use splat_overload::overload; -// ### Limitations -// -// We want `c_bool` here, but rust only has `c_char` , so `is_empty` converts the -// `char` back to bool . use std::ffi::{c_char, c_size_t, c_void}; use std::marker::PhantomData; @@ -44,11 +40,14 @@ impl StdStack { StdStack(stack, PhantomData) } + // ### Limitations + // + // We want `c_bool` here, but rust only has `c_char` , so `is_empty` converts the + // `char` back to bool . char is FFI safe, but rust bool is not fn is_empty(&self) -> bool { let slf = self.0 as *const c_void; let empty = unsafe { cpp!([slf as "const std::stack*"] -> c_char as "char" { - // char is FFI safe, but rust bool is not return slf->empty(); }) }; diff --git a/cpp-overloads-in-rust.md b/cpp-overloads-in-rust.md index 0656300..3b68aa7 100644 --- a/cpp-overloads-in-rust.md +++ b/cpp-overloads-in-rust.md @@ -28,6 +28,7 @@ See the Limitations section below the table for more details. | *Template Classes* | Constructors | Accessors | Modifiers | Transforms | | [forward_list] | ✅ | 🌗⚙️[^1] | 🌗⚙️?[^2] | ✅ | | [hash] | ✅ | ✅ | | | +| [stack] | ✅ | ⚙️[^5] | ? | | | [unordered_multiset] | ✅ | ✅⚙️[^3] | ✅ | ?[^4] | | TODO | ? | ? | ? | ? | @@ -38,12 +39,14 @@ Transforms: Rearrange the items in a list class, called as `instance->sort(...)` [forward_list]: https://github.com/rustfoundation/overloading-macros/blob/main/cpp-overload-test/src/stdcpp/forward_list.rs [hash]: https://github.com/rustfoundation/overloading-macros/blob/main/cpp-overload-test/src/stdcpp/hash.rs +[stack]: https://github.com/rustfoundation/overloading-macros/blob/main/cpp-overload-test/src/stdcpp/stack.rs [unordered_multiset]: https://github.com/rustfoundation/overloading-macros/blob/main/cpp-overload-test/src/stdcpp/unordered_multiset.rs [^1]: Rust and C++ iterators have different semantics, using adapter types is an ergonomic workaround. [^2]: `insert_after` and `splice_after` still need to be analysed. [^3]: The overload macro can't overload on `&self` vs `&mut self`, which limits representing some accessor overloads. [^4]: `extract`, `merge`, and `erase_if` still need analysis. These are C++17/C++20 node handle and non-member function overloads. +[^5]: `top` overloads differ only by `const` (`T& top()` and `const T& top() const`) , `&self` vs `&mut self` in Rust , which the overload macro can't represent. ## Limitations From 42dfc6e0d5184d3bafd525c8a706b2d3fb5a3057 Mon Sep 17 00:00:00 2001 From: Siddhi sahu Date: Sat, 7 Nov 2026 15:38:12 +0530 Subject: [PATCH 7/8] add top workaround, skip push overloasds Signed-off-by: Siddhi sahu --- cpp-overload-test/examples/stdcpp-stack.rs | 7 +++++++ cpp-overload-test/examples/stdcpp-stack.stderr | 2 +- cpp-overload-test/src/stdcpp/stack.rs | 8 ++++++++ cpp-overloads-in-rust.md | 4 ++-- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/cpp-overload-test/examples/stdcpp-stack.rs b/cpp-overload-test/examples/stdcpp-stack.rs index d2d0dba..aea9c1f 100644 --- a/cpp-overload-test/examples/stdcpp-stack.rs +++ b/cpp-overload-test/examples/stdcpp-stack.rs @@ -39,6 +39,13 @@ overload! { /// involved. It will not be same as C++, where both functions are /// called top. But its how Rust normally does it, Vec has first() and first_mut() /// ANd Rust users would find it natural. + /// + /// The other option is like in the `forward_list::front` , take the stack as a normal + /// argument and not as self, like `top(this: &'static StdStack)` and + /// `top(this: &'static mut StdStack)` . but the thing is the macro, doesnt support + /// lifetimes , so the reference has to be static, and the stack has to be leaked , + /// which is very awkward to use and the callers write `StdStack::top(&stack)` + /// and not `stack.top()` fn top(&self) where T:Sized { todo!() } diff --git a/cpp-overload-test/examples/stdcpp-stack.stderr b/cpp-overload-test/examples/stdcpp-stack.stderr index d64b540..db4a0ec 100644 --- a/cpp-overload-test/examples/stdcpp-stack.stderr +++ b/cpp-overload-test/examples/stdcpp-stack.stderr @@ -6,7 +6,7 @@ error: proc macro panicked 24 | | /// ### Incompatibilities 25 | | /// ... | -50 | | } +57 | | } | |_^ | = help: message: all overloads must have the same receiver kind (&self, &mut self, self, or no receiver), got top: &self and top: &mut self diff --git a/cpp-overload-test/src/stdcpp/stack.rs b/cpp-overload-test/src/stdcpp/stack.rs index a77fbbb..0158e47 100644 --- a/cpp-overload-test/src/stdcpp/stack.rs +++ b/cpp-overload-test/src/stdcpp/stack.rs @@ -54,6 +54,14 @@ impl StdStack { empty != 0 } + // ### Limitations + // + // c++ `push` has two overloads; `push(const T&)` copies the values in and + // `push(T&&)` moves it in. They only differ by `&` and `&&`. + // + // Only one is wrapped here, as a helper outside `overload!` . + // The `&`/`&&` difference is covered by copy and move constructors (`new(&StdStack)` and + // `new(&mut StdStack)`). fn push(&mut self, value: T) { let slf: *mut c_void = self.0; unsafe { diff --git a/cpp-overloads-in-rust.md b/cpp-overloads-in-rust.md index c20533c..8d8df7b 100644 --- a/cpp-overloads-in-rust.md +++ b/cpp-overloads-in-rust.md @@ -28,7 +28,7 @@ See the Limitations section below the table for more details. | *Template Classes* | Constructors | Accessors | Modifiers | Transforms | | [forward_list] | ✅ | 🌗⚙️[^1] | 🌗⚙️?[^2] | ✅ | | [hash] | ✅ | ✅ | | | -| [stack] | ✅ | ⚙️[^5] | ? | | +| [stack] | ✅ | ⚙️[^6] | ? | | | [unordered_map] | ✅ | 🌗⚙️[^5] | 🌗⚙️ | | | [unordered_multiset] | ✅ | ✅⚙️[^3] | ✅ | ?[^4] | | [time_point] | ✅ | ✅ | | ✅ | @@ -50,8 +50,8 @@ Transforms: Rearrange the items in a list class, called as `instance->sort(...)` [^2]: `insert_after` and `splice_after` still need to be analysed. [^3]: The overload macro can't overload on `&self` vs `&mut self`, which limits representing some accessor overloads. [^4]: `extract`, `merge`, and `erase_if` still need analysis. These are C++17/C++20 node handle and non-member function overloads. -[^5]: `top` overloads differ only by `const` (`T& top()` and `const T& top() const`) , `&self` vs `&mut self` in Rust , which the overload macro can't represent. [^5]: `find` and `max_load_factor` use associated functions instead of methods due to macro limitations with `&self` vs `&mut self`. +[^6]: `top` overloads differ only by `const` (`T& top()` and `const T& top() const`) , `&self` vs `&mut self` in Rust , which the overload macro can't represent. ## Limitations From 47312e10c034ae483ec05af3c027dc1a2cf9d184 Mon Sep 17 00:00:00 2001 From: Siddhi sahu Date: Mon, 9 Nov 2026 21:16:23 +0530 Subject: [PATCH 8/8] comment why move_from/copy_from picks the move/copy constructor Signed-off-by: Siddhi sahu --- cpp-overload-test/src/stdcpp/stack.rs | 8 ++++++++ cpp-overloads-in-rust.md | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/cpp-overload-test/src/stdcpp/stack.rs b/cpp-overload-test/src/stdcpp/stack.rs index 0158e47..ea5ccfd 100644 --- a/cpp-overload-test/src/stdcpp/stack.rs +++ b/cpp-overload-test/src/stdcpp/stack.rs @@ -96,6 +96,9 @@ impl StdStack { } } + // *other is const lvalue (from &StdStack) , so only the copy constructor + // stack(const stack&) matched, The move constructor cant take a + // const object, so moving isnot possible here. fn copy_from(other: &StdStack) -> StdStack { let other = other.0 as *const c_void; let stack = unsafe { @@ -106,6 +109,11 @@ impl StdStack { StdStack(stack, PhantomData) } + // std::move(*other) marks the stack as an rvalue + // so overload picks the move constructor stack (stack&&) instead + // of copy constructor + // Do it in one steps: a named variable will be lvalue again and get + // copied, other is non-const , which is what make the move possible fn move_from(other: &mut StdStack) -> StdStack { let other = other.0; let stack = unsafe { diff --git a/cpp-overloads-in-rust.md b/cpp-overloads-in-rust.md index 8d8df7b..fa05f5d 100644 --- a/cpp-overloads-in-rust.md +++ b/cpp-overloads-in-rust.md @@ -51,7 +51,7 @@ Transforms: Rearrange the items in a list class, called as `instance->sort(...)` [^3]: The overload macro can't overload on `&self` vs `&mut self`, which limits representing some accessor overloads. [^4]: `extract`, `merge`, and `erase_if` still need analysis. These are C++17/C++20 node handle and non-member function overloads. [^5]: `find` and `max_load_factor` use associated functions instead of methods due to macro limitations with `&self` vs `&mut self`. -[^6]: `top` overloads differ only by `const` (`T& top()` and `const T& top() const`) , `&self` vs `&mut self` in Rust , which the overload macro can't represent. +[^6]: `top` overloads differ only by `const` (`T& top()` and `const T& top() const`) , `&self` vs `&mut self` in Rust, which the overload macro can't represent. ## Limitations