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
4 changes: 4 additions & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ jobs:
- name: Check diagnostic output
# To bless (update the expected diagnostics), change '/tmp' to 'splat-overload-diagnostics/src/bin',
# and disable color output.
# Or just do `cargo build --package splat-overload-diagnostics --bin NAME > splat-overload-diagnostics/src/bin/NAME.stderr 2>&1`
# and delete the cargo Updating/Download*/Compiling logs.
# FIXME: turn this into a script so we can run it locally.
run: |
cargo fmt --package splat-overload-diagnostics -- --check
Expand Down Expand Up @@ -200,6 +202,8 @@ jobs:
- name: Check C++ overload fail cases
# To bless (update the expected output), change '/tmp' to 'cpp-overload-test/examples',
# and disable color output.
# Or just do `cargo build --package cpp-overload-test --example NAME > cpp-overload-test/examples/NAME.stderr 2>&1`
# and delete the cargo Updating/Download*/Compiling logs.
# FIXME: turn this into a script so contributors can run it locally.
run: |
echo "Checking must-fail example builds:"
Expand Down
139 changes: 136 additions & 3 deletions cpp-overload-test/examples/stdcpp-forward-list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,141 @@
//!
//! The `cpp!` macro doesn't work here, because of technical limitations it can only run one build
//! per crate. (Examples and binaries are built separately from `lib.rs`.)
//! To add C++ code here, use /* ... */ code comment blocks.
//! To add C++ code here, use /* ... */ code comment blocks, or just skip it.
//!
//! ### Potential Resolutions
//!
//! There isn't a clear equivalent of list initializers in Rust, so if we decided the initializer
//! list overloads were inexpressible in Rust, all overloads would be compatible. (And initializer
//! lists could be supported using the slice or iterator overloads.)
#![feature(splat, tuple_trait, c_size_t)]
#![allow(incomplete_features)]
#![allow(unused_braces)]

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

/// A wrapper struct to hold the returned C++ pointer, with the `T` fake generic type.
/// We also fake the C++ list pointer with a Rust vector to help with type checking.
#[expect(dead_code, reason = "Incompatible overloads can't be used")]
struct StdForwardListT(Vec<T>);

/// Workaround for missing generic support in the `overload!` macro.
type T = std::ffi::c_size_t;

fn main() {
const _: () = panic!("There are no failing overloads for C++ `std::forward_list` yet");
// 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!()
}

/// Construct a list filled with `count` instances of the given value.
fn new(_value: T, _count: c_size_t) -> StdForwardListT {
todo!()
}

/// Construct a list from the supplied item.
///
/// ### Incompatibilities
///
/// This overload has the same types as `new(count)` when `T` is `c_size_t`, but different
/// semantics:
/// - `new(count)` fills the list with the default value of `T` repeated`count` times.
/// - `new(value)` fills the list with one instance of `value`.
fn new(_value: T) -> StdForwardListT {
todo!()
}

/// Construct a list from the supplied 2 items.
///
/// ### Incompatibilities
///
/// This overload has the same types as `new(value, count)` when `T` is `c_size_t`, but different
/// semantics:
/// - `new(value, count)` fills the list with `count` instances of `value`.
/// - `new(a, b)` fills the list with two values: `a` and `b`.
fn new(_a: T, _b: T) -> StdForwardListT {
todo!()
}
}
}

/// A wrapper struct to hold the returned C++ pointer, with the `U` fake generic type.
/// We also fake the C++ list pointer with a Rust vector to help with type checking.
#[expect(dead_code, reason = "Incompatible overloads can't be used")]
struct StdForwardListU(Vec<U>);

/// Workaround for missing generic support in the `overload!` macro.
type U = StdForwardListU;

// This overload set has overloads which are compatible, but have poor ergonomics,
// when `U` is `StdForwardListU` (which is possible with some boxed types).
overload! {
impl StdForwardListU {
/// Clone list items into a new list from a shared list reference.
fn newer(_other: &StdForwardListU) -> StdForwardListU where U: Clone {
todo!()
}

/// Move list items into a new list from a mutable list reference.
fn newer(_other: &mut StdForwardListU) -> StdForwardListU {
todo!()
}

/// Construct a list from the supplied item.
///
/// ### Potential Overlap
///
/// This overload has similar types to `new(&/&mut other)` when `U` is `StdForwardListU`,
/// but different semantics:
/// - `new(&/&mut other)` clones or moves the list items into a new list.
/// - `new(value)` fills the list with one instance of `value`.
///
/// Due to the references, this is technically compatible. But the ergonomics are likely
/// to be poor, particularly when auto-ref and auto-deref are used.
fn newer(_a: U) -> StdForwardListU {
todo!()
}
}
}

/// A wrapper struct to hold the returned C++ pointer, with the `V` fake generic type.
/// We also fake the C++ list pointer with a Rust vector to help with type checking.
#[expect(dead_code, reason = "Incompatible overloads can't be used")]
struct StdForwardListV(Vec<V>);

/// Workaround for missing generic support in the `overload!` macro.
/// Currently this type alias fails compilation very early due to cycle checking, but with
/// generics the *possibility* of an identical impl existing is enough to make compilation fail,
/// even if it can't be implemented in practice.
//type V<'v> = &'v mut dyn Iterator<Item = V<'v>>;
type V = Box<dyn Iterator<Item = VCycleBreaker>>;
type VCycleBreaker = ();

// This overload set has overloads which are incompatible when `V` is
// `&mut dyn Iterator<Item = V>`. This is a contrived example, but trait solving would fail anyway.
overload! {
impl StdForwardListV {
/// Construct a list from an iterator.
fn newest(_iter: &mut dyn Iterator<Item = V>) -> StdForwardListV {
todo!()
}

/// Construct a list from the supplied items.
///
/// ### Incompatibilities
///
/// This overload has the same type as `new(iter)` when `V` is
/// `&mut dyn Iterator<Item = V>`, but different semantics:
/// - `new(iter)` constructs a list from the items in the iterator.
/// - `new(a)` constructs a list from a single item (where the item is an iterator).
fn newest(_a: V) -> StdForwardListV {
todo!()
}
}
}

pub fn main() {}
40 changes: 33 additions & 7 deletions cpp-overload-test/examples/stdcpp-forward-list.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,34 @@
error[E0080]: evaluation panicked: There are no failing overloads for C++ `std::forward_list` yet
--> cpp-overload-test/examples/stdcpp-forward-list.rs:8:19
|
8 | const _: () = panic!("There are no failing overloads for C++ `std::forward_list` yet");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `main::_` failed here
error[E0119]: conflicting implementations of trait `NewArgs<StdForwardListT>` for type `(usize,)`
--> cpp-overload-test/examples/stdcpp-forward-list.rs:29:1
|
29 | / overload! {
30 | | impl StdForwardListT {
31 | | /// Construct a list with `count` default-constructed items.
32 | | fn new(_count: c_size_t) -> StdForwardListT {
... |
65 | | }
| | ^
| | |
| |_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)

For more information about this error, try `rustc --explain E0080`.
error: could not compile `cpp-overload-test` (example "stdcpp-forward-list") due to 1 previous error
error[E0119]: conflicting implementations of trait `NewArgs<StdForwardListT>` for type `(usize, usize)`
--> cpp-overload-test/examples/stdcpp-forward-list.rs:29:1
|
29 | / overload! {
30 | | impl StdForwardListT {
31 | | /// Construct a list with `count` default-constructed items.
32 | | fn new(_count: c_size_t) -> StdForwardListT {
... |
65 | | }
| | ^
| | |
| |_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-forward-list") due to 2 previous errors
2 changes: 1 addition & 1 deletion cpp-overload-test/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Test C++ overloads that can be successfully represented in Rust.
//! Each type in the C++ standard library has a module under `stdcpp`.

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

/// The C++ standard library.
Expand Down
Loading
Loading