Skip to content

Commit 3e0ed1b

Browse files
authored
Merge pull request #981 from dtolnay/denyelided
Fill in elided lifetimes in generated code
2 parents ebf7275 + 5e07662 commit 3e0ed1b

File tree

5 files changed

+106
-25
lines changed

5 files changed

+106
-25
lines changed

macro/src/derive.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ fn struct_debug(strct: &Struct, span: Span) -> TokenStream {
140140

141141
quote_spanned! {span=>
142142
impl #generics ::cxx::core::fmt::Debug for #ident #generics {
143-
fn fmt(&self, formatter: &mut ::cxx::core::fmt::Formatter) -> ::cxx::core::fmt::Result {
143+
fn fmt(&self, formatter: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
144144
formatter.debug_struct(#struct_name)
145145
#(.field(#field_names, &self.#fields))*
146146
.finish()
@@ -251,7 +251,7 @@ fn enum_debug(enm: &Enum, span: Span) -> TokenStream {
251251

252252
quote_spanned! {span=>
253253
impl ::cxx::core::fmt::Debug for #ident {
254-
fn fmt(&self, formatter: &mut ::cxx::core::fmt::Formatter) -> ::cxx::core::fmt::Result {
254+
fn fmt(&self, formatter: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
255255
match *self {
256256
#(#variants)*
257257
_ => ::cxx::core::write!(formatter, #fallback, self.repr),

macro/src/expand.rs

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ fn expand(ffi: Module, doc: Doc, attrs: OtherAttrs, apis: &[Api], types: &Types)
5353
for api in apis {
5454
if let Api::RustType(ety) = api {
5555
expanded.extend(expand_rust_type_import(ety));
56-
hidden.extend(expand_rust_type_assert_unpin(ety));
56+
hidden.extend(expand_rust_type_assert_unpin(ety, types));
5757
}
5858
}
5959

@@ -70,15 +70,15 @@ fn expand(ffi: Module, doc: Doc, attrs: OtherAttrs, apis: &[Api], types: &Types)
7070
let ident = &ety.name.rust;
7171
if !types.structs.contains_key(ident) && !types.enums.contains_key(ident) {
7272
expanded.extend(expand_cxx_type(ety));
73-
hidden.extend(expand_cxx_type_assert_pinned(ety));
73+
hidden.extend(expand_cxx_type_assert_pinned(ety, types));
7474
}
7575
}
7676
Api::CxxFunction(efn) => {
7777
expanded.extend(expand_cxx_function_shim(efn, types));
7878
}
7979
Api::RustType(ety) => {
8080
expanded.extend(expand_rust_type_impl(ety));
81-
hidden.extend(expand_rust_type_layout(ety));
81+
hidden.extend(expand_rust_type_layout(ety, types));
8282
}
8383
Api::RustFunction(efn) => hidden.extend(expand_rust_function_shim(efn, types)),
8484
Api::TypeAlias(alias) => {
@@ -186,6 +186,7 @@ fn expand_struct(strct: &Struct) -> TokenStream {
186186

187187
fn expand_struct_operators(strct: &Struct) -> TokenStream {
188188
let ident = &strct.name.rust;
189+
let generics = &strct.generics;
189190
let mut operators = TokenStream::new();
190191

191192
for derive in &strct.derives {
@@ -198,7 +199,7 @@ fn expand_struct_operators(strct: &Struct) -> TokenStream {
198199
operators.extend(quote_spanned! {span=>
199200
#[doc(hidden)]
200201
#[export_name = #link_name]
201-
extern "C" fn #local_name(lhs: &#ident, rhs: &#ident) -> bool {
202+
extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool {
202203
let __fn = concat!("<", module_path!(), #prevent_unwind_label);
203204
::cxx::private::prevent_unwind(__fn, || *lhs == *rhs)
204205
}
@@ -211,7 +212,7 @@ fn expand_struct_operators(strct: &Struct) -> TokenStream {
211212
operators.extend(quote_spanned! {span=>
212213
#[doc(hidden)]
213214
#[export_name = #link_name]
214-
extern "C" fn #local_name(lhs: &#ident, rhs: &#ident) -> bool {
215+
extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool {
215216
let __fn = concat!("<", module_path!(), #prevent_unwind_label);
216217
::cxx::private::prevent_unwind(__fn, || *lhs != *rhs)
217218
}
@@ -225,7 +226,7 @@ fn expand_struct_operators(strct: &Struct) -> TokenStream {
225226
operators.extend(quote_spanned! {span=>
226227
#[doc(hidden)]
227228
#[export_name = #link_name]
228-
extern "C" fn #local_name(lhs: &#ident, rhs: &#ident) -> bool {
229+
extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool {
229230
let __fn = concat!("<", module_path!(), #prevent_unwind_label);
230231
::cxx::private::prevent_unwind(__fn, || *lhs < *rhs)
231232
}
@@ -237,7 +238,7 @@ fn expand_struct_operators(strct: &Struct) -> TokenStream {
237238
operators.extend(quote_spanned! {span=>
238239
#[doc(hidden)]
239240
#[export_name = #link_name]
240-
extern "C" fn #local_name(lhs: &#ident, rhs: &#ident) -> bool {
241+
extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool {
241242
let __fn = concat!("<", module_path!(), #prevent_unwind_label);
242243
::cxx::private::prevent_unwind(__fn, || *lhs <= *rhs)
243244
}
@@ -250,7 +251,7 @@ fn expand_struct_operators(strct: &Struct) -> TokenStream {
250251
operators.extend(quote_spanned! {span=>
251252
#[doc(hidden)]
252253
#[export_name = #link_name]
253-
extern "C" fn #local_name(lhs: &#ident, rhs: &#ident) -> bool {
254+
extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool {
254255
let __fn = concat!("<", module_path!(), #prevent_unwind_label);
255256
::cxx::private::prevent_unwind(__fn, || *lhs > *rhs)
256257
}
@@ -262,7 +263,7 @@ fn expand_struct_operators(strct: &Struct) -> TokenStream {
262263
operators.extend(quote_spanned! {span=>
263264
#[doc(hidden)]
264265
#[export_name = #link_name]
265-
extern "C" fn #local_name(lhs: &#ident, rhs: &#ident) -> bool {
266+
extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool {
266267
let __fn = concat!("<", module_path!(), #prevent_unwind_label);
267268
::cxx::private::prevent_unwind(__fn, || *lhs >= *rhs)
268269
}
@@ -277,7 +278,7 @@ fn expand_struct_operators(strct: &Struct) -> TokenStream {
277278
#[doc(hidden)]
278279
#[export_name = #link_name]
279280
#[allow(clippy::cast_possible_truncation)]
280-
extern "C" fn #local_name(this: &#ident) -> usize {
281+
extern "C" fn #local_name #generics(this: &#ident #generics) -> usize {
281282
let __fn = concat!("<", module_path!(), #prevent_unwind_label);
282283
::cxx::private::prevent_unwind(__fn, || ::cxx::private::hash(this))
283284
}
@@ -396,10 +397,13 @@ fn expand_cxx_type(ety: &ExternType) -> TokenStream {
396397
}
397398
}
398399

399-
fn expand_cxx_type_assert_pinned(ety: &ExternType) -> TokenStream {
400+
fn expand_cxx_type_assert_pinned(ety: &ExternType, types: &Types) -> TokenStream {
400401
let ident = &ety.name.rust;
401402
let infer = Token![_](ident.span());
402403

404+
let resolve = types.resolve(ident);
405+
let lifetimes = resolve.generics.to_underscore_lifetimes();
406+
403407
quote! {
404408
let _: fn() = {
405409
// Derived from https://github.com/nvzqz/static-assertions-rs.
@@ -424,7 +428,7 @@ fn expand_cxx_type_assert_pinned(ety: &ExternType) -> TokenStream {
424428
// `_` can be resolved and this can compile. Fails to compile if
425429
// user has added a manual Unpin impl for their opaque C++ type as
426430
// then `__AmbiguousIfImpl<__Invalid>` also exists.
427-
<#ident as __AmbiguousIfImpl<#infer>>::infer
431+
<#ident #lifetimes as __AmbiguousIfImpl<#infer>>::infer
428432
};
429433
}
430434
}
@@ -833,21 +837,25 @@ fn expand_rust_type_impl(ety: &ExternType) -> TokenStream {
833837
impls
834838
}
835839

836-
fn expand_rust_type_assert_unpin(ety: &ExternType) -> TokenStream {
840+
fn expand_rust_type_assert_unpin(ety: &ExternType, types: &Types) -> TokenStream {
837841
let ident = &ety.name.rust;
838842
let begin_span = Token![::](ety.type_token.span);
839843
let unpin = quote_spanned! {ety.semi_token.span=>
840844
#begin_span cxx::core::marker::Unpin
841845
};
846+
847+
let resolve = types.resolve(ident);
848+
let lifetimes = resolve.generics.to_underscore_lifetimes();
849+
842850
quote_spanned! {ident.span()=>
843851
let _ = {
844852
fn __AssertUnpin<T: ?::cxx::core::marker::Sized + #unpin>() {}
845-
__AssertUnpin::<#ident>
853+
__AssertUnpin::<#ident #lifetimes>
846854
};
847855
}
848856
}
849857

850-
fn expand_rust_type_layout(ety: &ExternType) -> TokenStream {
858+
fn expand_rust_type_layout(ety: &ExternType, types: &Types) -> TokenStream {
851859
// Rustc will render as follows if not sized:
852860
//
853861
// type TheirType;
@@ -868,6 +876,9 @@ fn expand_rust_type_layout(ety: &ExternType) -> TokenStream {
868876
let local_sizeof = format_ident!("__sizeof_{}", ety.name.rust);
869877
let local_alignof = format_ident!("__alignof_{}", ety.name.rust);
870878

879+
let resolve = types.resolve(ident);
880+
let lifetimes = resolve.generics.to_underscore_lifetimes();
881+
871882
quote_spanned! {ident.span()=>
872883
{
873884
#[doc(hidden)]
@@ -877,12 +888,12 @@ fn expand_rust_type_layout(ety: &ExternType) -> TokenStream {
877888
#[doc(hidden)]
878889
#[export_name = #link_sizeof]
879890
extern "C" fn #local_sizeof() -> usize {
880-
__AssertSized::<#ident>().size()
891+
__AssertSized::<#ident #lifetimes>().size()
881892
}
882893
#[doc(hidden)]
883894
#[export_name = #link_alignof]
884895
extern "C" fn #local_alignof() -> usize {
885-
__AssertSized::<#ident>().align()
896+
__AssertSized::<#ident #lifetimes>().align()
886897
}
887898
}
888899
}
@@ -1393,7 +1404,7 @@ fn expand_unique_ptr(
13931404
quote_spanned! {end_span=>
13941405
#unsafe_token impl #impl_generics ::cxx::private::UniquePtrTarget for #ident #ty_generics {
13951406
#[doc(hidden)]
1396-
fn __typename(f: &mut ::cxx::core::fmt::Formatter) -> ::cxx::core::fmt::Result {
1407+
fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
13971408
f.write_str(#name)
13981409
}
13991410
#[doc(hidden)]
@@ -1485,7 +1496,7 @@ fn expand_shared_ptr(
14851496
quote_spanned! {end_span=>
14861497
#unsafe_token impl #impl_generics ::cxx::private::SharedPtrTarget for #ident #ty_generics {
14871498
#[doc(hidden)]
1488-
fn __typename(f: &mut ::cxx::core::fmt::Formatter) -> ::cxx::core::fmt::Result {
1499+
fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
14891500
f.write_str(#name)
14901501
}
14911502
#[doc(hidden)]
@@ -1545,7 +1556,7 @@ fn expand_weak_ptr(key: NamedImplKey, types: &Types, explicit_impl: Option<&Impl
15451556
quote_spanned! {end_span=>
15461557
#unsafe_token impl #impl_generics ::cxx::private::WeakPtrTarget for #ident #ty_generics {
15471558
#[doc(hidden)]
1548-
fn __typename(f: &mut ::cxx::core::fmt::Formatter) -> ::cxx::core::fmt::Result {
1559+
fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
15491560
f.write_str(#name)
15501561
}
15511562
#[doc(hidden)]
@@ -1660,7 +1671,7 @@ fn expand_cxx_vector(
16601671
quote_spanned! {end_span=>
16611672
#unsafe_token impl #impl_generics ::cxx::private::VectorElement for #elem #ty_generics {
16621673
#[doc(hidden)]
1663-
fn __typename(f: &mut ::cxx::core::fmt::Formatter) -> ::cxx::core::fmt::Result {
1674+
fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
16641675
f.write_str(#name)
16651676
}
16661677
#[doc(hidden)]

macro/src/generics.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use crate::syntax::instantiate::NamedImplKey;
22
use crate::syntax::resolve::Resolution;
3-
use crate::syntax::Impl;
3+
use crate::syntax::{Impl, Lifetimes};
44
use proc_macro2::TokenStream;
55
use quote::ToTokens;
6-
use syn::Token;
6+
use syn::{Lifetime, Token};
77

88
pub struct ImplGenerics<'a> {
99
explicit_impl: Option<&'a Impl>,
@@ -61,3 +61,31 @@ impl<'a> ToTokens for TyGenerics<'a> {
6161
}
6262
}
6363
}
64+
65+
pub struct UnderscoreLifetimes<'a> {
66+
generics: &'a Lifetimes,
67+
}
68+
69+
impl Lifetimes {
70+
pub fn to_underscore_lifetimes(&self) -> UnderscoreLifetimes {
71+
UnderscoreLifetimes { generics: self }
72+
}
73+
}
74+
75+
impl<'a> ToTokens for UnderscoreLifetimes<'a> {
76+
fn to_tokens(&self, tokens: &mut TokenStream) {
77+
let Lifetimes {
78+
lt_token,
79+
lifetimes,
80+
gt_token,
81+
} = self.generics;
82+
lt_token.to_tokens(tokens);
83+
for pair in lifetimes.pairs() {
84+
let (lifetime, punct) = pair.into_tuple();
85+
let lifetime = Lifetime::new("'_", lifetime.span());
86+
lifetime.to_tokens(tokens);
87+
punct.to_tokens(tokens);
88+
}
89+
gt_token.to_tokens(tokens);
90+
}
91+
}

tests/ui/deny_elided_lifetimes.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#![deny(elided_lifetimes_in_paths)]
2+
3+
#[cxx::bridge]
4+
mod ffi {
5+
#[derive(PartialEq, PartialOrd, Hash)]
6+
struct Struct<'a> {
7+
reference: &'a i32,
8+
}
9+
10+
extern "Rust" {
11+
type Rust<'a>;
12+
}
13+
14+
unsafe extern "C++" {
15+
type Cpp<'a>;
16+
17+
fn lifetime_named<'a>(s: &'a i32) -> UniquePtr<Cpp<'a>>;
18+
19+
fn lifetime_underscore(s: &i32) -> UniquePtr<Cpp<'_>>;
20+
21+
fn lifetime_elided(s: &i32) -> UniquePtr<Cpp>;
22+
}
23+
}
24+
25+
pub struct Rust<'a>(&'a i32);
26+
27+
fn main() {}

tests/ui/deny_elided_lifetimes.stderr

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: hidden lifetime parameters in types are deprecated
2+
--> tests/ui/deny_elided_lifetimes.rs:21:50
3+
|
4+
21 | fn lifetime_elided(s: &i32) -> UniquePtr<Cpp>;
5+
| ^^^ expected named lifetime parameter
6+
|
7+
note: the lint level is defined here
8+
--> tests/ui/deny_elided_lifetimes.rs:1:9
9+
|
10+
1 | #![deny(elided_lifetimes_in_paths)]
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
12+
help: consider using the `'_` lifetime
13+
|
14+
21 | fn lifetime_elided(s: &i32) -> UniquePtr<Cpp<'_>>;
15+
| ~~~~~~~

0 commit comments

Comments
 (0)