Skip to content

Commit 3267913

Browse files
committed
Add support for renamed type aliases
1 parent 8f822ad commit 3267913

File tree

12 files changed

+79
-4
lines changed

12 files changed

+79
-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
@@ -1222,11 +1222,18 @@ fn expand_type_alias_verify(alias: &TypeAlias, types: &Types) -> TokenStream {
12221222
let type_id = type_id(&alias.name);
12231223
let begin_span = alias.type_token.span;
12241224
let end_span = alias.semi_token.span;
1225-
let begin = quote_spanned!(begin_span=> ::cxx::private::verify_extern_type::<);
12261225
let end = quote_spanned!(end_span=> >);
12271226

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

12321239
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
@@ -496,7 +496,9 @@ pub type Vector<T> = CxxVector<T>;
496496
pub mod private {
497497
pub use crate::c_char::c_char;
498498
pub use crate::cxx_vector::VectorElement;
499-
pub use crate::extern_type::{verify_extern_kind, verify_extern_type};
499+
pub use crate::extern_type::{
500+
verify_extern_kind, verify_extern_type, verify_extern_type_renamed,
501+
};
500502
pub use crate::function::FatFunction;
501503
pub use crate::hash::hash;
502504
pub use crate::opaque::Opaque;

Diff for: syntax/attrs.rs

+9
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
@@ -152,6 +153,14 @@ pub fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser) -> Othe
152153
**variants_from_header = Some(attr);
153154
continue;
154155
}
156+
} else if attr.path.is_ident("renamed") {
157+
if let Err(err) = Nothing::parse.parse2(attr.tokens.clone()) {
158+
cx.push(err);
159+
}
160+
if let Some(is_renamed) = &mut parser.is_renamed {
161+
**is_renamed = true;
162+
continue;
163+
}
155164
} else if attr.path.is_ident("allow")
156165
|| attr.path.is_ident("warn")
157166
|| attr.path.is_ident("deny")

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
@@ -860,6 +860,7 @@ fn parse_type_alias(
860860
let mut cxx_name = None;
861861
let mut rust_name = None;
862862
let mut attrs = attrs.clone();
863+
let mut is_renamed = false;
863864
attrs.extend(attrs::parse(
864865
cx,
865866
unparsed_attrs,
@@ -870,6 +871,7 @@ fn parse_type_alias(
870871
namespace: Some(&mut namespace),
871872
cxx_name: Some(&mut cxx_name),
872873
rust_name: Some(&mut rust_name),
874+
is_renamed: Some(&mut is_renamed),
873875
..Default::default()
874876
},
875877
));
@@ -895,6 +897,7 @@ fn parse_type_alias(
895897
eq_token,
896898
ty,
897899
semi_token,
900+
is_renamed,
898901
}))
899902
}
900903

Diff for: tests/ffi/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@ mod other {
347347
pub struct D {
348348
pub d: u64,
349349
}
350+
pub type DRenamed = D;
350351

351352
#[repr(C)]
352353
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
@@ -378,3 +378,9 @@ fn test_raw_ptr() {
378378
assert_eq!(2025, unsafe { ffi::c_take_const_ptr(c3) });
379379
assert_eq!(2025, unsafe { ffi::c_take_mut_ptr(c3 as *mut ffi::C) }); // deletes c3
380380
}
381+
382+
#[test]
383+
fn test_renamed() {
384+
let d = ffi2::DRenamed { d: 42 };
385+
check!(ffi2::c_take_renamed(d, 42));
386+
}

0 commit comments

Comments
 (0)