Skip to content

Commit 071a560

Browse files
committed
Merge pull request 1670 from anforowicz/test-that-original-lifetimes-are-used-in-impls
2 parents f0a0e24 + baf8f5c commit 071a560

File tree

2 files changed

+91
-1
lines changed

2 files changed

+91
-1
lines changed

macro/src/tests.rs

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@ use syn::File;
77
fn bridge(cxx_bridge: TokenStream) -> String {
88
let module = syn::parse2::<Module>(cxx_bridge).unwrap();
99
let tokens = expand::bridge(module).unwrap();
10-
let file = syn::parse2::<File>(tokens).unwrap();
10+
let file = match syn::parse2::<File>(tokens.clone()) {
11+
Ok(file) => file,
12+
Err(err) => {
13+
eprintln!("The code below is syntactically invalid: {err}:");
14+
eprintln!("{tokens}");
15+
panic!("`expand::bridge` should generate syntactically valid code");
16+
}
17+
};
1118
let pretty = prettyplease::unparse(&file);
1219
eprintln!("{0:/<80}\n{pretty}{0:/<80}", "");
1320
pretty
@@ -84,3 +91,68 @@ fn test_vec_string() {
8491
assert!(rs.contains("v: &::cxx::private::RustVec<::cxx::alloc::string::String>"));
8592
assert!(rs.contains("fn __foo(v: &::cxx::alloc::vec::Vec<::cxx::alloc::string::String>)"));
8693
}
94+
95+
#[test]
96+
fn test_mangling_covers_cpp_namespace_of_vec_elements() {
97+
let rs = bridge(quote! {
98+
mod ffi {
99+
#[namespace = "test_namespace"]
100+
struct Context { x: i32 }
101+
impl Vec<Context> {}
102+
}
103+
});
104+
105+
// Mangling must include Context's C++ namespace to avoid colliding the
106+
// symbol names for two identically named structs in different namespaces.
107+
assert!(rs.contains("export_name = \"cxxbridge1$rust_vec$test_namespace$Context$set_len\""));
108+
}
109+
110+
#[test]
111+
fn test_struct_with_lifetime() {
112+
let rs = bridge(quote! {
113+
mod ffi {
114+
struct StructWithLifetime<'a> {
115+
s: &'a str,
116+
}
117+
extern "Rust" {
118+
fn f(_: UniquePtr<StructWithLifetime<>>);
119+
}
120+
}
121+
});
122+
123+
// Regression test for <https://github.com/dtolnay/cxx/pull/1658#discussion_r2529463814>
124+
// which generated this invalid code:
125+
//
126+
// impl<'a> ::cxx::memory::UniquePtrTarget for StructWithLifetime < > < 'a > {
127+
//
128+
// Invalid syntax in the output code would already have caused the test
129+
// helper `bridge` to panic above. But for completeness this assertion
130+
// verifies the intended code has been generated.
131+
assert!(rs.contains("impl<'a> ::cxx::memory::UniquePtrTarget for StructWithLifetime<'a> {"));
132+
133+
// Assertions for other places that refer to `StructWithLifetime`.
134+
assert!(rs.contains("pub struct StructWithLifetime<'a> {"));
135+
assert!(rs.contains("cast::<StructWithLifetime<'a>>()"));
136+
assert!(rs.contains("fn __f(arg0: ::cxx::UniquePtr<StructWithLifetime>) {"));
137+
assert!(rs.contains("impl<'a> self::Drop for super::StructWithLifetime<'a>"));
138+
}
139+
140+
#[test]
141+
fn test_original_lifetimes_used_in_impls() {
142+
let rs = bridge(quote! {
143+
mod ffi {
144+
struct Context<'sess> {
145+
session: &'sess str,
146+
}
147+
struct Server<'srv> {
148+
ctx: UniquePtr<Context<'srv>>,
149+
}
150+
struct Client<'clt> {
151+
ctx: UniquePtr<Context<'clt>>,
152+
}
153+
}
154+
});
155+
156+
// Verify which lifetime name ('sess, 'srv, 'clt) gets used for this impl.
157+
assert!(rs.contains("impl<'sess> ::cxx::memory::UniquePtrTarget for Context<'sess> {"));
158+
}

tests/ffi/lib.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,19 @@ pub mod ffi {
388388
impl UniquePtr<Array> {}
389389
}
390390

391+
#[rustfmt::skip]
392+
#[cxx::bridge(namespace = "tests")]
393+
pub mod ffi_no_rustfmt {
394+
// Rustfmt would replace `StructWithLifetime2<>` by `StructWithLifetime2`,
395+
// but the test is meant to cover specifically the former spelling.
396+
pub struct StructWithLifetime2<'a> {
397+
s: &'a str,
398+
}
399+
extern "Rust" {
400+
fn r_take_unique_ptr_of_struct_with_lifetime2(_: UniquePtr<StructWithLifetime2<>>);
401+
}
402+
}
403+
391404
mod other {
392405
use cxx::kind::{Opaque, Trivial};
393406
use cxx::{type_id, CxxString, ExternType};
@@ -691,6 +704,11 @@ fn r_take_enum(e: ffi::Enum) {
691704
let _ = e;
692705
}
693706

707+
fn r_take_unique_ptr_of_struct_with_lifetime2(
708+
_: cxx::UniquePtr<ffi_no_rustfmt::StructWithLifetime2>,
709+
) {
710+
}
711+
694712
fn r_try_return_void() -> Result<(), Error> {
695713
Ok(())
696714
}

0 commit comments

Comments
 (0)