From cda3f41e8892f8eff976c4f57cd0bd2f41c0e300 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 25 Sep 2026 13:26:48 +0200 Subject: [PATCH 1/6] Add skip criteria to README --- cpp-overload-test/src/stdcpp/forward_list.rs | 4 ++++ cpp-overloads-in-rust.md | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/cpp-overload-test/src/stdcpp/forward_list.rs b/cpp-overload-test/src/stdcpp/forward_list.rs index 228f7cb..483df51 100644 --- a/cpp-overload-test/src/stdcpp/forward_list.rs +++ b/cpp-overload-test/src/stdcpp/forward_list.rs @@ -303,6 +303,8 @@ overload! { // Accessors: `front(...)` overload! { impl StdForwardList { + /// Get the first element of the list as a constant reference. + /// /// ### Limitations /// /// The `overload!` macro can't overload on `&self` vs `&mut self`, because it has to @@ -391,6 +393,8 @@ pub fn test_forward_list() { let from_initializer_list = StdForwardList::new(3, 2, 1); assert_eq!(from_initializer_list.front_const(), Some(&3)); + // Accessors: `front(...)` + // // ### Workaround // // Leak these lists to get static references to them. This would never work in production. diff --git a/cpp-overloads-in-rust.md b/cpp-overloads-in-rust.md index db97b9e..340a6be 100644 --- a/cpp-overloads-in-rust.md +++ b/cpp-overloads-in-rust.md @@ -101,3 +101,14 @@ These overloads have no equivalent in Rust: (`before_begin`/`begin`/`end`/`after_end`) - initializer list methods: these are also a common source of overload conflicts for C++ templated lists + +#### Equivalences & Supersets + +When the same overloaded functions are available on different classes, we only analyse the overload +on one of those classes. + +When one overloaded function takes the same argument sets (or a subset of the argument set) of +another overloaded function, we only analyse one of the argument sets. For example, +`unique()`/`unique(predicate)` and `sort()`/`sort(predicate)`. + +In some cases, we focus on the most "difficult" overload in a category, and skip the rest. From 08fe6ad21a3ecbd5809b143b7a1dfe7d25e9f841 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 25 Sep 2026 13:27:00 +0200 Subject: [PATCH 2/6] Add resize overload --- cpp-overload-test/src/stdcpp/forward_list.rs | 45 +++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/cpp-overload-test/src/stdcpp/forward_list.rs b/cpp-overload-test/src/stdcpp/forward_list.rs index 483df51..519aaf8 100644 --- a/cpp-overload-test/src/stdcpp/forward_list.rs +++ b/cpp-overload-test/src/stdcpp/forward_list.rs @@ -204,6 +204,25 @@ impl StdForwardList { } } + // Transforms: internal implementations for `resize(...)`, `unique(...)` + fn resize_default(&mut self, count: c_size_t) { + let slf: *mut c_void = self.0; + unsafe { + cpp!([slf as "std::forward_list*", count as "size_t"] { + slf->resize(count); + }) + } + } + + fn resize_with(&mut self, count: c_size_t, value: T) { + let slf: *mut c_void = self.0; + unsafe { + cpp!([slf as "std::forward_list*", count as "size_t", value as "int"] { + slf->resize(count, value); + }) + } + } + // List checks fn is_empty(&self) -> bool { let slf = self.0 as *const c_void; @@ -341,12 +360,29 @@ overload! { StdForwardList::front_const(this) } + /// Get the first element of the list as a mutable reference. pub fn front(this: &'static mut StdForwardList) -> Option<&'static mut T> where T: Sized { StdForwardList::front_mut(this) } } } +// Transforms: `resize(...)`, `unique(...)` +// We skip `sort(...)` because its argument set is almost identical to `unique(...)`. +overload! { + impl StdForwardList { + /// Resize the list to the given size, filling any new elements with the default value. + pub fn resize(&mut self, count: c_size_t) { + self.resize_default(count) + } + + /// Resize the list to the given size, filling any new elements with the given value. + pub fn resize(&mut self, count: c_size_t, value: T) { + self.resize_with(count, value) + } + } +} + #[test] pub fn test_forward_list() { // Constructors: `new(...)` @@ -369,7 +405,7 @@ pub fn test_forward_list() { // // The `as_slice` call is required to match the overload, an array doesn't automatically coerce. // FIXME: maybe add a const generic overload for arrays. - let from_slice = StdForwardList::new([1, 2, 3].as_slice()); + let mut from_slice = StdForwardList::new([1, 2, 3].as_slice()); assert_eq!(from_slice.front_const(), Some(&1)); // ### Limitations @@ -410,4 +446,11 @@ pub fn test_forward_list() { StdForwardList::front(static_mut(repeat_with)), Some(&mut 42) ); + + // Transforms: `resize(...)`, `unique(...)` + from_slice.resize(0); + assert!(from_slice.is_empty()); + let mut resized_list = StdForwardList::new(); + resized_list.resize(1, 42); + assert_eq!(resized_list.front_const(), Some(&42)); } From 50f92f55e1d72009f11bfa0709a0be1ae04a60a4 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 25 Sep 2026 13:54:36 +0200 Subject: [PATCH 3/6] Add forward_list::unique --- cpp-overload-test/src/stdcpp/forward_list.rs | 54 +++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/cpp-overload-test/src/stdcpp/forward_list.rs b/cpp-overload-test/src/stdcpp/forward_list.rs index 519aaf8..2b941a4 100644 --- a/cpp-overload-test/src/stdcpp/forward_list.rs +++ b/cpp-overload-test/src/stdcpp/forward_list.rs @@ -21,6 +21,10 @@ cpp! {{ #include #include #include + + // The `cpp!` macro can't handle C/C++ function type syntax, so we have to declare function + // types here. + typedef bool BinaryPredicate(const int&, const int&); }} /// A wrapper struct to hold the returned C++ pointer. @@ -223,7 +227,27 @@ impl StdForwardList { } } - // List checks + fn unique_equals(&mut self) -> c_size_t { + let slf: *mut c_void = self.0; + unsafe { + cpp!([slf as "std::forward_list*"] -> c_size_t as "size_t" { + return slf->unique(); + }) + } + } + + fn unique_with(&mut self, eq_predicate: extern "C" fn(&T, &T) -> bool) -> c_size_t { + let slf: *mut c_void = self.0; + unsafe { + // The `cpp!` macro can't handle C/C++ function type syntax, so we have to declare the + // type separately above. + cpp!([slf as "std::forward_list*", eq_predicate as "BinaryPredicate*"] -> c_size_t as "size_t" { + return slf->unique(eq_predicate); + }) + } + } + + // List checks (not overloaded) fn is_empty(&self) -> bool { let slf = self.0 as *const c_void; let empty = unsafe { @@ -383,6 +407,23 @@ overload! { } } +overload! { + impl StdForwardList { + /// Remove all consecutive duplicate elements from the list. + /// Returns the number of elements removed. + pub fn unique(&mut self) -> c_size_t { + self.unique_equals() + } + + /// Remove all consecutive duplicate elements from the list, using the given predicate to + /// compare elements as equal. + /// Returns the number of elements removed. + pub fn unique(&mut self, eq_predicate: extern "C" fn(&T, &T) -> bool) -> c_size_t { + self.unique_with(eq_predicate) + } + } +} + #[test] pub fn test_forward_list() { // Constructors: `new(...)` @@ -453,4 +494,15 @@ pub fn test_forward_list() { let mut resized_list = StdForwardList::new(); resized_list.resize(1, 42); assert_eq!(resized_list.front_const(), Some(&42)); + + let mut unique_list = StdForwardList::new([1, 2, 2, 3, 3, 3, 1].as_slice()); + assert_eq!(unique_list.unique(), 3); + assert_eq!(unique_list.front_const(), Some(&1)); + + let mut unique_list = StdForwardList::new([1, 2, 2, 3, 3, 3, 1].as_slice()); + extern "C" fn predicate(a: &T, b: &T) -> bool { + a == b + } + assert_eq!(unique_list.unique(predicate), 3); + assert_eq!(unique_list.front_const(), Some(&1)); } From 220fd1bf546fdf4f68255e555dae37ddffffffcb Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 25 Sep 2026 14:06:54 +0200 Subject: [PATCH 4/6] Add forward_list::merge --- cpp-overload-test/src/stdcpp/forward_list.rs | 57 ++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/cpp-overload-test/src/stdcpp/forward_list.rs b/cpp-overload-test/src/stdcpp/forward_list.rs index 2b941a4..da23970 100644 --- a/cpp-overload-test/src/stdcpp/forward_list.rs +++ b/cpp-overload-test/src/stdcpp/forward_list.rs @@ -208,6 +208,31 @@ impl StdForwardList { } } + // Modifiers: internal implementations for `merge(...)` + fn merge_from(self: &mut StdForwardList, other: &mut StdForwardList) { + let slf: *mut c_void = self.0; + let other: *mut c_void = other.0; + unsafe { + cpp!([slf as "std::forward_list*", other as "std::forward_list*"] { + slf->merge(*other); + }) + } + } + + fn merge_with( + self: &mut StdForwardList, + other: &mut StdForwardList, + less_than_predicate: extern "C" fn(&T, &T) -> bool, + ) { + let slf: *mut c_void = self.0; + let other: *mut c_void = other.0; + unsafe { + cpp!([slf as "std::forward_list*", other as "std::forward_list*", less_than_predicate as "BinaryPredicate*"] { + slf->merge(*other, less_than_predicate); + }) + } + } + // Transforms: internal implementations for `resize(...)`, `unique(...)` fn resize_default(&mut self, count: c_size_t) { let slf: *mut c_void = self.0; @@ -391,6 +416,23 @@ overload! { } } +// Modifiers: `merge(...)` +overload! { + impl StdForwardList { + /// Move elements from `other` into this list, preserving sort order. + /// Both lists must be sorted. + pub fn merge(&mut self, other: &mut StdForwardList) { + self.merge_from(other) + } + + /// Move elements from `other` into this list, preserving sort order with the given + /// predicate. Both lists must be sorted according to that predicate. + pub fn merge(&mut self, other: &mut StdForwardList, less_than_predicate: extern "C" fn(&T, &T) -> bool) { + self.merge_with(other, less_than_predicate) + } + } +} + // Transforms: `resize(...)`, `unique(...)` // We skip `sort(...)` because its argument set is almost identical to `unique(...)`. overload! { @@ -488,6 +530,21 @@ pub fn test_forward_list() { Some(&mut 42) ); + // Modifiers: `merge(...)` + let mut merge_into_list = StdForwardList::new([1, 3, 5].as_slice()); + let mut merge_from_list = StdForwardList::new([0, 2, 4, 6].as_slice()); + merge_into_list.merge(&mut merge_from_list); + assert_eq!(merge_into_list.front_const(), Some(&0)); + + let mut merge_into_list = StdForwardList::new([5, 3, 1].as_slice()); + let mut merge_from_list = StdForwardList::new([6, 4, 2, 0].as_slice()); + // This predicate is deliberately inverted. + extern "C" fn more_than_predicate(a: &T, b: &T) -> bool { + a > b + } + merge_into_list.merge(&mut merge_from_list, more_than_predicate); + assert_eq!(merge_into_list.front_const(), Some(&6)); + // Transforms: `resize(...)`, `unique(...)` from_slice.resize(0); assert!(from_slice.is_empty()); From 65d6c959918fc3638530cf4bed71adb23a8a6c71 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 25 Sep 2026 14:10:22 +0200 Subject: [PATCH 5/6] Update forward_list compatibility table --- cpp-overloads-in-rust.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/cpp-overloads-in-rust.md b/cpp-overloads-in-rust.md index 340a6be..20b449c 100644 --- a/cpp-overloads-in-rust.md +++ b/cpp-overloads-in-rust.md @@ -19,15 +19,15 @@ See the Limitations section below the table for more details. ? Needs Analysis
*blank* No C++ Overloads
-| C++ Standard Library Class | Constructors | Accessors | Modifiers | Transforms | -| :------------------------- | :----------- | :-------- | :-------- | :--------- | -| *Free Functions* | Constructors | Accessors | Modifiers | Transforms | -| TODO | | ? | ? | ? | -| *Non-Template Classes* | Constructors | Accessors | Modifiers | Transforms | -| TODO | ? | ? | ? | ? | -| *Template Classes* | Constructors | Accessors | Modifiers | Transforms | -| [forward_list] | ✅ | 🌗⚙️ | ? | ?[^1] | -| TODO | ? | ? | ? | ? | +| C++ Standard Library Class | Constructors | Accessors | Modifiers | Transforms | +| :------------------------- | :----------- | :-------- | :--------- | :--------- | +| *Free Functions* | Constructors | Accessors | Modifiers | Transforms | +| TODO | | ? | ? | ? | +| *Non-Template Classes* | Constructors | Accessors | Modifiers | Transforms | +| TODO | ? | ? | ? | ? | +| *Template Classes* | Constructors | Accessors | Modifiers | Transforms | +| [forward_list] | ✅ | 🌗⚙️ | 🌗⚙️?[^1] | ✅ | +| TODO | ? | ? | ? | ? | Constructors: Create an instance of the class, called as `Class::Class(...)`
Accessors: Get information about the class, called as `instance->get(...)`
@@ -36,7 +36,7 @@ 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 -[^1]: TODO: are [C++ predicate functions](https://en.cppreference.com/cpp/container/forward_list/unique) with const refs ABI-compatible with Rust? +[^1]: Mostly caused by the differences between Rust and C++ iterators, could be overcome with type wrappers. ## Limitations From 133b04ea2e4082019e9f30c00dc4d0f88b76006c Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 25 Sep 2026 14:20:48 +0200 Subject: [PATCH 6/6] Fix line numbers in stderr file --- .../examples/stdcpp-forward-list.stderr | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/cpp-overload-test/examples/stdcpp-forward-list.stderr b/cpp-overload-test/examples/stdcpp-forward-list.stderr index bac7a48..5aa638b 100644 --- a/cpp-overload-test/examples/stdcpp-forward-list.stderr +++ b/cpp-overload-test/examples/stdcpp-forward-list.stderr @@ -1,25 +1,25 @@ error: proc macro panicked - --> cpp-overload-test/examples/stdcpp-forward-list.rs:151:1 + --> cpp-overload-test/examples/stdcpp-forward-list.rs:157:1 | -151 | / overload! { -152 | | impl StdForwardList { -153 | | /// ### Incompatibilities -154 | | /// +157 | / overload! { +158 | | impl StdForwardList { +159 | | /// ### Incompatibilities +160 | | /// ... | -165 | | } +171 | | } | |_^ | = help: message: all overloads must have the same receiver kind (&self, &mut self, self, or no receiver), got front: &self and front: &mut self error[E0119]: conflicting implementations of trait `NewArgs` for type `(usize,)` - --> cpp-overload-test/examples/stdcpp-forward-list.rs:29:1 + --> cpp-overload-test/examples/stdcpp-forward-list.rs:35:1 | -29 | / overload! { -30 | | impl StdForwardListT { -31 | | /// Construct a list with `count` default-constructed items. -32 | | fn new(_count: c_size_t) -> StdForwardListT { +35 | / overload! { +36 | | impl StdForwardListT { +37 | | /// Construct a list with `count` default-constructed items. +38 | | fn new(_count: c_size_t) -> StdForwardListT { ... | -65 | | } +71 | | } | | ^ | | | | |_first implementation here @@ -28,14 +28,14 @@ error[E0119]: conflicting implementations of trait `NewArgs` fo = note: this error originates in the macro `overload` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0119]: conflicting implementations of trait `NewArgs` for type `(usize, usize)` - --> cpp-overload-test/examples/stdcpp-forward-list.rs:29:1 + --> cpp-overload-test/examples/stdcpp-forward-list.rs:35:1 | -29 | / overload! { -30 | | impl StdForwardListT { -31 | | /// Construct a list with `count` default-constructed items. -32 | | fn new(_count: c_size_t) -> StdForwardListT { +35 | / overload! { +36 | | impl StdForwardListT { +37 | | /// Construct a list with `count` default-constructed items. +38 | | fn new(_count: c_size_t) -> StdForwardListT { ... | -65 | | } +71 | | } | | ^ | | | | |_first implementation here