Repository navigation
Fix implicit construction in rules - #569
Merged
Merged
Conversation
joaotgouveia
pushed a commit
to joaotgouveia/cpp2rust
that referenced
this pull request
Oct 30, 2026
Closes Cpp2Rust#567 and Cpp2Rust#568 C++ has 3 ways of implicitly constructing a value: * conversion constructor, `struct Foo { Foo(int i) {} }` * conversion operator, `structure Foo { operator int() () {} }` * integer conversions, `vector(InputIt first, InputIt last)` a range of longs can initialize a vector of ints A rule that does implicit conversion cannot know which of the three versions is used. We need a common interface for all three that rules can use. This PR adds CppFrom. Structs that have one of the two: conversion constructor or conversion operator, implement CppFrom using a derived trait. We cannot use Rust's From because From has value semantics while C++ can have reference semantics, for example: `struct Foo { Foo(const OtherStructThatHasCloneSideEffects&) {} }`. ```cpp struct S { int x; S(int i) : x(i) {} }; ``` ```rust // Derive CppFrom for the method called `new` that receives // the argument `i32` using `value` semantics pub struct S { pub x: i32, } impl S { pub fn new(i: i32) -> Self { Self { x: i } } } // expanded by the derive impl CppFrom<i32> for S { fn cpp_from(src: Ptr<i32>) -> Self { S::new(src.read()) } } ``` --- Rules that need implicit construction are written like this: ```rs // Conversion constructor of pair: pair<T3, T4> -> pair<T1, T2> fn f24<T1: CppFrom<T3>, T2: CppFrom<T4>, T3, T4>( a0: (Value<T3>, Value<T4>), ) -> (Value<T1>, Value<T2>) { let __a0 = a0; ( Rc::new(RefCell::new(T1::cpp_from(__a0.0.as_pointer()))), Rc::new(RefCell::new(T2::cpp_from(__a0.1.as_pointer()))), ) } ``` --- Some notes: * to optimize the generated code. I added a new Rules IR node called GenericCall. If the GenericCall is cpp_form and the source and destination are integers, don't use the fully qualified call `T1::call_from(<T2 expr>)`, use `T2 as T1` * I replaced the Default node with GeneriCall, T1::default() is also a generic call
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #567 and #568
C++ has 3 ways of implicitly constructing a value:
struct Foo { Foo(int i) {} }structure Foo { operator int() () {} }vector(InputIt first, InputIt last)a range of longs can initialize a vector of intsA rule that does implicit conversion cannot know which of the three versions is used. We need a common interface for all three that rules can use.
This PR adds CppFrom. Structs that have one of the two: conversion constructor or conversion operator, implement CppFrom using a derived trait. We cannot use Rust's From because From has value semantics while C++ can have reference semantics, for example:
struct Foo { Foo(const OtherStructThatHasCloneSideEffects&) {} }.Rules that need implicit construction are written like this:
Some notes:
T1::call_from(<T2 expr>), useT2 as T1