Skip to content
88 changes: 88 additions & 0 deletions cpp-overload-test/examples/stdcpp-vector.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//! Demonstrate incompatible Rust translations of C++ `std::vector` overloads.
//! Expected compiler output is in `stdcpp-vector.stderr`; working overloads are in
//! `src/stdcpp/vector.rs`. This example uses Rust-only stand-ins because the crate's
//! `cpp!` build scans the library, not separately compiled examples.
//!
//! ### Incompatibilities
//!
//! Setting the element alias `T` to `c_size_t` makes the one-element initializer-list
//! signature identical to the count constructor, and the two-element signature
//! identical to the fill constructor. The generated argument-trait implementations
//! overlap. Explicit argument casts cannot distinguish identical types.
//! This collision comes from translating initializer lists into separate arguments:
//! C++ has a distinct `initializer_list<T>` parameter and braced-initialization syntax.
//!
//! The macro also rejects `front(&self)` and `front(&mut self)` in one overload set.
//! Its single dispatch method must have one receiver kind, so it cannot directly
//! represent the const and non-const C++ accessor pair.
//!
//! ### Macro ergonomics
//!
//! FIXME: The `(usize, usize)` conflict diagnostic points at the overload block
//! and displays the one-argument constructor instead of the conflicting two-argument
//! constructors. Improve the macro's generated spans so the error identifies the
//! count-and-value and two-element initializer-list overloads.
//!
//! ### Workarounds
//!
//! Give initializer-list input a distinct wrapper type, or use separate constructor
//! names for element lists and counts. Accepting slices instead is another API option,
//! but the existing slice bridge invokes the iterator-pair constructor and would not
//! demonstrate the initializer-list constructor.
//!
//! Use separate `front` and `front_mut` methods for the accessor pair. An alternative
//! worth testing is associated-function overloads with explicit `&Vector` and
//! `&mut Vector` arguments instead of receivers. A working borrowed accessor must
//! tie the returned reference's lifetime to the vector and prevent invalidating
//! mutations while that reference is borrowed.
//!
//! C++ signatures: <https://eel.is/c++draft/vector.overview>.

#![feature(splat, tuple_trait, c_size_t)]
#![allow(incomplete_features)]
#![allow(unused_braces)]

use splat_overload::overload;
use std::ffi::c_size_t;

type T = c_size_t;

#[expect(dead_code, reason = "Incompatible overloads cannot be called")]
struct StdVectorT(Vec<T>);

overload! {
impl StdVectorT {
fn new(_count: c_size_t) -> StdVectorT {
todo!()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like there might have been a version control snafu? Is it expected that these are todo!()?

@teor2345 teor2345 Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The examples are test files that show that overloads conflict in Rust (or can't be implemented in C++). So todo!() is ok here, there's not much point filling in the C++ code when the Rust code will never work.

See the example code here where the overloads conflict when T is size_t:

// This overload set has overloads which are incompatible when `T` is `c_size_t`.
overload! {
impl StdForwardListT {
/// Construct a list with `count` default-constructed items.
fn new(_count: c_size_t) -> StdForwardListT {
todo!()
}

Think of them like a cheap version of Rust compiler UI tests, they also come with a stderr output file.

Also, this is step 2 of the PR, this is @thunderseethe's decision. If he thinks that the step 1 work is complete, he can move on to reviewing step 2.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, these were intentional placeholders in the compile-fail example, not a version-control mistake. The test checks conflicting signatures, so the bodies never run.

}

fn new(_count: c_size_t, _value: T) -> StdVectorT {
todo!()
}

fn new(_value: T) -> StdVectorT {
todo!()
}

fn new(_a: T, _b: T) -> StdVectorT {
todo!()
}
}
}

#[expect(dead_code, reason = "Incompatible overloads cannot be called")]
struct StdVectorFront(Vec<std::ffi::c_int>);

overload! {
impl StdVectorFront {
fn front(&self) -> Option<&std::ffi::c_int> {
self.0.first()
}

fn front(&mut self) -> Option<&mut std::ffi::c_int> {
self.0.first_mut()
}
}
}

fn main() {}
47 changes: 47 additions & 0 deletions cpp-overload-test/examples/stdcpp-vector.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
error: proc macro panicked
--> cpp-overload-test/examples/stdcpp-vector.rs:76:1
|
76 | / overload! {
77 | | impl StdVectorFront {
78 | | fn front(&self) -> Option<&std::ffi::c_int> {
79 | | self.0.first()
... |
86 | | }
| |_^
|
= 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<StdVectorT>` for type `(usize,)`
--> cpp-overload-test/examples/stdcpp-vector.rs:53:1
|
53 | / overload! {
54 | | impl StdVectorT {
55 | | fn new(_count: c_size_t) -> StdVectorT {
56 | | todo!()
... |
71 | | }
| | ^
| | |
| |_first implementation here
| conflicting implementation for `(usize,)`
|
= 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<StdVectorT>` for type `(usize, usize)`
--> cpp-overload-test/examples/stdcpp-vector.rs:53:1
|
53 | / overload! {
54 | | impl StdVectorT {
55 | | fn new(_count: c_size_t) -> StdVectorT {
56 | | todo!()
... |
71 | | }
| | ^
| | |
| |_first implementation here
| conflicting implementation for `(usize, usize)`
|
= note: this error originates in the macro `overload` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0119`.
error: could not compile `cpp-overload-test` (example "stdcpp-vector") due to 3 previous errors
1 change: 1 addition & 0 deletions cpp-overload-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub mod stdcpp {
pub mod forward_list;
pub mod hash;
pub mod unordered_multiset;
pub mod vector;
}

// Checks that `build.rs` rebuilds changed `cpp!` code, see `rerun-check.sh`.
Expand Down
Loading
Loading