Skip to content

Commit 3c1ce2a

Browse files
committed
Add support for renamed type aliases
1 parent eb06f52 commit 3c1ce2a

File tree

12 files changed

+92
-4
lines changed

12 files changed

+92
-4
lines changed

Diff for: book/src/extern-c++.md

+27
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,33 @@ value, and include it in `struct`s that you have declared to `cxx::bridge`. Your
286286
claim about the triviality of the C++ type will be checked by a `static_assert`
287287
in the generated C++ side of the binding.
288288
289+
### Handling renamed or aliased types
290+
291+
By default, the name of an Extern C++ type must match the `Id` of the Rust
292+
type's `ExternType` impl. For example, a `i32` in Rust may only be used as a
293+
`std::int32_t` in C++.
294+
295+
In the case where a single Rust type maps to multiple C++ types, or a different
296+
type than in its `ExternType` impl, then you can use the `#[renamed]` attribute
297+
in the `extern "C++"` block to indicate that the type is intentionally renamed.
298+
299+
For example, if we wanted to call an extern C++ function called `may_fail` that
300+
returns a Windows-style `HRESULT` and we wanted to use the name `HRESULT` in the
301+
Rust definition to note that the return value is a result and not a general
302+
number, then we can add `#[renamed]` to the type alias:
303+
304+
```rust,noplayground
305+
#[cxx::bridge]
306+
mod ffi {
307+
extern "C++" {
308+
#[renamed]
309+
type HRESULT = i32;
310+
311+
fn may_fail() -> HRESULT;
312+
}
313+
}
314+
```
315+
289316
## Explicit shim trait impls
290317

291318
This is a somewhat niche feature, but important when you need it.

Diff for: macro/src/expand.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -1223,11 +1223,18 @@ fn expand_type_alias_verify(alias: &TypeAlias, types: &Types) -> TokenStream {
12231223
let type_id = type_id(&alias.name);
12241224
let begin_span = alias.type_token.span;
12251225
let end_span = alias.semi_token.span;
1226-
let begin = quote_spanned!(begin_span=> ::cxx::private::verify_extern_type::<);
12271226
let end = quote_spanned!(end_span=> >);
12281227

1229-
let mut verify = quote! {
1230-
const _: fn() = #begin #ident, #type_id #end;
1228+
let mut verify = if alias.is_renamed {
1229+
let begin = quote_spanned!(begin_span=> ::cxx::private::verify_extern_type_renamed::<);
1230+
quote! {
1231+
const _: fn() = #begin #ident #end;
1232+
}
1233+
} else {
1234+
let begin = quote_spanned!(begin_span=> ::cxx::private::verify_extern_type::<);
1235+
quote! {
1236+
const _: fn() = #begin #ident, #type_id #end;
1237+
}
12311238
};
12321239

12331240
if types.required_trivial.contains_key(&alias.name.rust) {

Diff for: src/extern_type.rs

+3
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,9 @@ mod private {
183183
#[doc(hidden)]
184184
pub fn verify_extern_type<T: ExternType<Id = Id>, Id>() {}
185185

186+
#[doc(hidden)]
187+
pub fn verify_extern_type_renamed<T: ExternType>() {}
188+
186189
#[doc(hidden)]
187190
pub fn verify_extern_kind<T: ExternType<Kind = Kind>, Kind: self::Kind>() {}
188191

Diff for: src/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,9 @@ pub type Vector<T> = CxxVector<T>;
499499
pub mod private {
500500
pub use crate::c_char::c_char;
501501
pub use crate::cxx_vector::VectorElement;
502-
pub use crate::extern_type::{verify_extern_kind, verify_extern_type};
502+
pub use crate::extern_type::{
503+
verify_extern_kind, verify_extern_type, verify_extern_type_renamed,
504+
};
503505
pub use crate::function::FatFunction;
504506
pub use crate::hash::hash;
505507
pub use crate::opaque::Opaque;

Diff for: syntax/attrs.rs

+22
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub struct Parser<'a> {
3636
pub cxx_name: Option<&'a mut Option<ForeignName>>,
3737
pub rust_name: Option<&'a mut Option<Ident>>,
3838
pub variants_from_header: Option<&'a mut Option<Attribute>>,
39+
pub is_renamed: Option<&'a mut bool>,
3940
pub ignore_unrecognized: bool,
4041

4142
// Suppress clippy needless_update lint ("struct update has no effect, all
@@ -153,6 +154,19 @@ pub fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser) -> Othe
153154
**variants_from_header = Some(attr);
154155
continue;
155156
}
157+
} else if attr_path.is_ident("renamed") {
158+
match parse_renamed_attribute(&attr.meta) {
159+
Ok(_) => {
160+
if let Some(is_renamed) = &mut parser.is_renamed {
161+
**is_renamed = true;
162+
continue;
163+
}
164+
}
165+
Err(err) => {
166+
cx.push(err);
167+
break;
168+
}
169+
}
156170
} else if attr_path.is_ident("allow")
157171
|| attr_path.is_ident("warn")
158172
|| attr_path.is_ident("deny")
@@ -282,6 +296,14 @@ fn parse_rust_name_attribute(meta: &Meta) -> Result<Ident> {
282296
Err(Error::new_spanned(meta, "unsupported rust_name attribute"))
283297
}
284298

299+
fn parse_renamed_attribute(meta: &Meta) -> Result<()> {
300+
if let Meta::Path(_) = meta {
301+
Ok(())
302+
} else {
303+
Err(Error::new_spanned(meta, "unsupported renamed attribute"))
304+
}
305+
}
306+
285307
#[derive(Clone)]
286308
pub struct OtherAttrs(Vec<Attribute>);
287309

Diff for: syntax/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ pub struct TypeAlias {
158158
pub eq_token: Token![=],
159159
pub ty: RustType,
160160
pub semi_token: Token![;],
161+
pub is_renamed: bool,
161162
}
162163

163164
pub struct Impl {

Diff for: syntax/parse.rs

+3
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,7 @@ fn parse_type_alias(
859859
let mut cxx_name = None;
860860
let mut rust_name = None;
861861
let mut attrs = attrs.clone();
862+
let mut is_renamed = false;
862863
attrs.extend(attrs::parse(
863864
cx,
864865
unparsed_attrs,
@@ -869,6 +870,7 @@ fn parse_type_alias(
869870
namespace: Some(&mut namespace),
870871
cxx_name: Some(&mut cxx_name),
871872
rust_name: Some(&mut rust_name),
873+
is_renamed: Some(&mut is_renamed),
872874
..Default::default()
873875
},
874876
));
@@ -894,6 +896,7 @@ fn parse_type_alias(
894896
eq_token,
895897
ty,
896898
semi_token,
899+
is_renamed,
897900
}))
898901
}
899902

Diff for: tests/ffi/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ mod other {
349349
pub struct D {
350350
pub d: u64,
351351
}
352+
pub type DRenamed = D;
352353

353354
#[repr(C)]
354355
pub struct E {

Diff for: tests/ffi/module.rs

+6
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ pub mod ffi2 {
2121
include!("tests/ffi/tests.h");
2222

2323
type D = crate::other::D;
24+
#[renamed]
25+
type DRenamed = crate::other::DRenamed;
2426
type E = crate::other::E;
2527
#[namespace = "F"]
2628
type F = crate::other::f::F;
@@ -30,6 +32,9 @@ pub mod ffi2 {
3032
#[namespace = "H"]
3133
type H;
3234

35+
#[renamed]
36+
type Int64Alias = i64;
37+
3338
fn c_take_trivial_ptr(d: UniquePtr<D>);
3439
fn c_take_trivial_ref(d: &D);
3540
fn c_take_trivial_mut_ref(d: &mut D);
@@ -56,6 +61,7 @@ pub mod ffi2 {
5661
fn c_return_ns_opaque_ptr() -> UniquePtr<F>;
5762
fn c_return_ns_unique_ptr() -> UniquePtr<H>;
5863
fn c_take_ref_ns_c(h: &H);
64+
fn c_take_renamed(d: DRenamed, val: Int64Alias);
5965

6066
#[namespace = "other"]
6167
fn ns_c_take_trivial(d: D);

Diff for: tests/ffi/tests.cc

+6
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,12 @@ void c_take_opaque_ns_ref(const ::F::F &f) {
717717
}
718718
}
719719

720+
void c_take_renamed(DRenamed d, Int64Alias val) {
721+
if (d.d == val) {
722+
cxx_test_suite_set_correct();
723+
}
724+
}
725+
720726
std::unique_ptr<D> c_return_trivial_ptr() {
721727
auto d = std::unique_ptr<D>(new D());
722728
d->d = 30;

Diff for: tests/ffi/tests.h

+4
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ struct D {
6464
void c_take_trivial_ref_method() const;
6565
void c_take_trivial_mut_ref_method();
6666
};
67+
using DRenamed = D;
68+
using Int64Alias = uint64_t;
6769

6870
struct E {
6971
uint64_t e;
@@ -197,6 +199,8 @@ void c_take_trivial_pin_ref(const D &d);
197199
void c_take_trivial_pin_mut_ref(D &d);
198200
void c_take_trivial(D d);
199201

202+
void c_take_renamed(D d, Int64Alias val);
203+
200204
void c_take_trivial_ns_ptr(std::unique_ptr<::G::G> g);
201205
void c_take_trivial_ns_ref(const ::G::G &g);
202206
void c_take_trivial_ns(::G::G g);

Diff for: tests/test.rs

+6
Original file line numberDiff line numberDiff line change
@@ -379,3 +379,9 @@ fn test_raw_ptr() {
379379
assert_eq!(2025, unsafe { ffi::c_take_const_ptr(c3) });
380380
assert_eq!(2025, unsafe { ffi::c_take_mut_ptr(c3 as *mut ffi::C) }); // deletes c3
381381
}
382+
383+
#[test]
384+
fn test_renamed() {
385+
let d = ffi2::DRenamed { d: 42 };
386+
check!(ffi2::c_take_renamed(d, 42));
387+
}

0 commit comments

Comments
 (0)