From 3d14230eccc3ee6f00a52ef493abac212d5300b5 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 10 Dec 2021 12:11:29 -0800 Subject: [PATCH 1/4] Fill in elided lifetime in macro-generated code --- macro/src/derive.rs | 4 ++-- macro/src/expand.rs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/macro/src/derive.rs b/macro/src/derive.rs index 241d6deaa..afe85d1c2 100644 --- a/macro/src/derive.rs +++ b/macro/src/derive.rs @@ -140,7 +140,7 @@ fn struct_debug(strct: &Struct, span: Span) -> TokenStream { quote_spanned! {span=> impl #generics ::cxx::core::fmt::Debug for #ident #generics { - fn fmt(&self, formatter: &mut ::cxx::core::fmt::Formatter) -> ::cxx::core::fmt::Result { + fn fmt(&self, formatter: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result { formatter.debug_struct(#struct_name) #(.field(#field_names, &self.#fields))* .finish() @@ -251,7 +251,7 @@ fn enum_debug(enm: &Enum, span: Span) -> TokenStream { quote_spanned! {span=> impl ::cxx::core::fmt::Debug for #ident { - fn fmt(&self, formatter: &mut ::cxx::core::fmt::Formatter) -> ::cxx::core::fmt::Result { + fn fmt(&self, formatter: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result { match *self { #(#variants)* _ => ::cxx::core::write!(formatter, #fallback, self.repr), diff --git a/macro/src/expand.rs b/macro/src/expand.rs index 087150995..86023219e 100644 --- a/macro/src/expand.rs +++ b/macro/src/expand.rs @@ -1393,7 +1393,7 @@ fn expand_unique_ptr( quote_spanned! {end_span=> #unsafe_token impl #impl_generics ::cxx::private::UniquePtrTarget for #ident #ty_generics { #[doc(hidden)] - fn __typename(f: &mut ::cxx::core::fmt::Formatter) -> ::cxx::core::fmt::Result { + fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result { f.write_str(#name) } #[doc(hidden)] @@ -1485,7 +1485,7 @@ fn expand_shared_ptr( quote_spanned! {end_span=> #unsafe_token impl #impl_generics ::cxx::private::SharedPtrTarget for #ident #ty_generics { #[doc(hidden)] - fn __typename(f: &mut ::cxx::core::fmt::Formatter) -> ::cxx::core::fmt::Result { + fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result { f.write_str(#name) } #[doc(hidden)] @@ -1545,7 +1545,7 @@ fn expand_weak_ptr(key: NamedImplKey, types: &Types, explicit_impl: Option<&Impl quote_spanned! {end_span=> #unsafe_token impl #impl_generics ::cxx::private::WeakPtrTarget for #ident #ty_generics { #[doc(hidden)] - fn __typename(f: &mut ::cxx::core::fmt::Formatter) -> ::cxx::core::fmt::Result { + fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result { f.write_str(#name) } #[doc(hidden)] @@ -1660,7 +1660,7 @@ fn expand_cxx_vector( quote_spanned! {end_span=> #unsafe_token impl #impl_generics ::cxx::private::VectorElement for #elem #ty_generics { #[doc(hidden)] - fn __typename(f: &mut ::cxx::core::fmt::Formatter) -> ::cxx::core::fmt::Result { + fn __typename(f: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result { f.write_str(#name) } #[doc(hidden)] From e0966f73965e7e68871e4c77496cebe287c785f0 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 10 Dec 2021 13:07:54 -0800 Subject: [PATCH 2/4] Fill in elided lifetimes on AssertUnpin and AssertSized --- macro/src/expand.rs | 30 ++++++++++++++++++++---------- macro/src/generics.rs | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/macro/src/expand.rs b/macro/src/expand.rs index 86023219e..8d4c383e8 100644 --- a/macro/src/expand.rs +++ b/macro/src/expand.rs @@ -53,7 +53,7 @@ fn expand(ffi: Module, doc: Doc, attrs: OtherAttrs, apis: &[Api], types: &Types) for api in apis { if let Api::RustType(ety) = api { expanded.extend(expand_rust_type_import(ety)); - hidden.extend(expand_rust_type_assert_unpin(ety)); + hidden.extend(expand_rust_type_assert_unpin(ety, types)); } } @@ -70,7 +70,7 @@ fn expand(ffi: Module, doc: Doc, attrs: OtherAttrs, apis: &[Api], types: &Types) let ident = &ety.name.rust; if !types.structs.contains_key(ident) && !types.enums.contains_key(ident) { expanded.extend(expand_cxx_type(ety)); - hidden.extend(expand_cxx_type_assert_pinned(ety)); + hidden.extend(expand_cxx_type_assert_pinned(ety, types)); } } Api::CxxFunction(efn) => { @@ -78,7 +78,7 @@ fn expand(ffi: Module, doc: Doc, attrs: OtherAttrs, apis: &[Api], types: &Types) } Api::RustType(ety) => { expanded.extend(expand_rust_type_impl(ety)); - hidden.extend(expand_rust_type_layout(ety)); + hidden.extend(expand_rust_type_layout(ety, types)); } Api::RustFunction(efn) => hidden.extend(expand_rust_function_shim(efn, types)), Api::TypeAlias(alias) => { @@ -396,10 +396,13 @@ fn expand_cxx_type(ety: &ExternType) -> TokenStream { } } -fn expand_cxx_type_assert_pinned(ety: &ExternType) -> TokenStream { +fn expand_cxx_type_assert_pinned(ety: &ExternType, types: &Types) -> TokenStream { let ident = &ety.name.rust; let infer = Token![_](ident.span()); + let resolve = types.resolve(ident); + let lifetimes = resolve.generics.to_underscore_lifetimes(); + quote! { let _: fn() = { // Derived from https://github.com/nvzqz/static-assertions-rs. @@ -424,7 +427,7 @@ fn expand_cxx_type_assert_pinned(ety: &ExternType) -> TokenStream { // `_` can be resolved and this can compile. Fails to compile if // user has added a manual Unpin impl for their opaque C++ type as // then `__AmbiguousIfImpl<__Invalid>` also exists. - <#ident as __AmbiguousIfImpl<#infer>>::infer + <#ident #lifetimes as __AmbiguousIfImpl<#infer>>::infer }; } } @@ -833,21 +836,25 @@ fn expand_rust_type_impl(ety: &ExternType) -> TokenStream { impls } -fn expand_rust_type_assert_unpin(ety: &ExternType) -> TokenStream { +fn expand_rust_type_assert_unpin(ety: &ExternType, types: &Types) -> TokenStream { let ident = &ety.name.rust; let begin_span = Token![::](ety.type_token.span); let unpin = quote_spanned! {ety.semi_token.span=> #begin_span cxx::core::marker::Unpin }; + + let resolve = types.resolve(ident); + let lifetimes = resolve.generics.to_underscore_lifetimes(); + quote_spanned! {ident.span()=> let _ = { fn __AssertUnpin() {} - __AssertUnpin::<#ident> + __AssertUnpin::<#ident #lifetimes> }; } } -fn expand_rust_type_layout(ety: &ExternType) -> TokenStream { +fn expand_rust_type_layout(ety: &ExternType, types: &Types) -> TokenStream { // Rustc will render as follows if not sized: // // type TheirType; @@ -868,6 +875,9 @@ fn expand_rust_type_layout(ety: &ExternType) -> TokenStream { let local_sizeof = format_ident!("__sizeof_{}", ety.name.rust); let local_alignof = format_ident!("__alignof_{}", ety.name.rust); + let resolve = types.resolve(ident); + let lifetimes = resolve.generics.to_underscore_lifetimes(); + quote_spanned! {ident.span()=> { #[doc(hidden)] @@ -877,12 +887,12 @@ fn expand_rust_type_layout(ety: &ExternType) -> TokenStream { #[doc(hidden)] #[export_name = #link_sizeof] extern "C" fn #local_sizeof() -> usize { - __AssertSized::<#ident>().size() + __AssertSized::<#ident #lifetimes>().size() } #[doc(hidden)] #[export_name = #link_alignof] extern "C" fn #local_alignof() -> usize { - __AssertSized::<#ident>().align() + __AssertSized::<#ident #lifetimes>().align() } } } diff --git a/macro/src/generics.rs b/macro/src/generics.rs index 3de0330ba..7862536d0 100644 --- a/macro/src/generics.rs +++ b/macro/src/generics.rs @@ -1,9 +1,9 @@ use crate::syntax::instantiate::NamedImplKey; use crate::syntax::resolve::Resolution; -use crate::syntax::Impl; +use crate::syntax::{Impl, Lifetimes}; use proc_macro2::TokenStream; use quote::ToTokens; -use syn::Token; +use syn::{Lifetime, Token}; pub struct ImplGenerics<'a> { explicit_impl: Option<&'a Impl>, @@ -61,3 +61,31 @@ impl<'a> ToTokens for TyGenerics<'a> { } } } + +pub struct UnderscoreLifetimes<'a> { + generics: &'a Lifetimes, +} + +impl Lifetimes { + pub fn to_underscore_lifetimes(&self) -> UnderscoreLifetimes { + UnderscoreLifetimes { generics: self } + } +} + +impl<'a> ToTokens for UnderscoreLifetimes<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let Lifetimes { + lt_token, + lifetimes, + gt_token, + } = self.generics; + lt_token.to_tokens(tokens); + for pair in lifetimes.pairs() { + let (lifetime, punct) = pair.into_tuple(); + let lifetime = Lifetime::new("'_", lifetime.span()); + lifetime.to_tokens(tokens); + punct.to_tokens(tokens); + } + gt_token.to_tokens(tokens); + } +} From 753f42ab369ea2b76c839d3f579f8a91ff4e4d0e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 10 Dec 2021 13:12:08 -0800 Subject: [PATCH 3/4] Fill in elided lifetimes on derived operators --- macro/src/expand.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/macro/src/expand.rs b/macro/src/expand.rs index 8d4c383e8..1e3c8da67 100644 --- a/macro/src/expand.rs +++ b/macro/src/expand.rs @@ -186,6 +186,7 @@ fn expand_struct(strct: &Struct) -> TokenStream { fn expand_struct_operators(strct: &Struct) -> TokenStream { let ident = &strct.name.rust; + let generics = &strct.generics; let mut operators = TokenStream::new(); for derive in &strct.derives { @@ -198,7 +199,7 @@ fn expand_struct_operators(strct: &Struct) -> TokenStream { operators.extend(quote_spanned! {span=> #[doc(hidden)] #[export_name = #link_name] - extern "C" fn #local_name(lhs: &#ident, rhs: &#ident) -> bool { + extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool { let __fn = concat!("<", module_path!(), #prevent_unwind_label); ::cxx::private::prevent_unwind(__fn, || *lhs == *rhs) } @@ -211,7 +212,7 @@ fn expand_struct_operators(strct: &Struct) -> TokenStream { operators.extend(quote_spanned! {span=> #[doc(hidden)] #[export_name = #link_name] - extern "C" fn #local_name(lhs: &#ident, rhs: &#ident) -> bool { + extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool { let __fn = concat!("<", module_path!(), #prevent_unwind_label); ::cxx::private::prevent_unwind(__fn, || *lhs != *rhs) } @@ -225,7 +226,7 @@ fn expand_struct_operators(strct: &Struct) -> TokenStream { operators.extend(quote_spanned! {span=> #[doc(hidden)] #[export_name = #link_name] - extern "C" fn #local_name(lhs: &#ident, rhs: &#ident) -> bool { + extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool { let __fn = concat!("<", module_path!(), #prevent_unwind_label); ::cxx::private::prevent_unwind(__fn, || *lhs < *rhs) } @@ -237,7 +238,7 @@ fn expand_struct_operators(strct: &Struct) -> TokenStream { operators.extend(quote_spanned! {span=> #[doc(hidden)] #[export_name = #link_name] - extern "C" fn #local_name(lhs: &#ident, rhs: &#ident) -> bool { + extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool { let __fn = concat!("<", module_path!(), #prevent_unwind_label); ::cxx::private::prevent_unwind(__fn, || *lhs <= *rhs) } @@ -250,7 +251,7 @@ fn expand_struct_operators(strct: &Struct) -> TokenStream { operators.extend(quote_spanned! {span=> #[doc(hidden)] #[export_name = #link_name] - extern "C" fn #local_name(lhs: &#ident, rhs: &#ident) -> bool { + extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool { let __fn = concat!("<", module_path!(), #prevent_unwind_label); ::cxx::private::prevent_unwind(__fn, || *lhs > *rhs) } @@ -262,7 +263,7 @@ fn expand_struct_operators(strct: &Struct) -> TokenStream { operators.extend(quote_spanned! {span=> #[doc(hidden)] #[export_name = #link_name] - extern "C" fn #local_name(lhs: &#ident, rhs: &#ident) -> bool { + extern "C" fn #local_name #generics(lhs: &#ident #generics, rhs: &#ident #generics) -> bool { let __fn = concat!("<", module_path!(), #prevent_unwind_label); ::cxx::private::prevent_unwind(__fn, || *lhs >= *rhs) } @@ -277,7 +278,7 @@ fn expand_struct_operators(strct: &Struct) -> TokenStream { #[doc(hidden)] #[export_name = #link_name] #[allow(clippy::cast_possible_truncation)] - extern "C" fn #local_name(this: &#ident) -> usize { + extern "C" fn #local_name #generics(this: &#ident #generics) -> usize { let __fn = concat!("<", module_path!(), #prevent_unwind_label); ::cxx::private::prevent_unwind(__fn, || ::cxx::private::hash(this)) } From 5e076627a776e22425065032ffa065dbd741743c Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 10 Dec 2021 13:24:20 -0800 Subject: [PATCH 4/4] Add ui test with denied elided lifetime --- tests/ui/deny_elided_lifetimes.rs | 27 +++++++++++++++++++++++++++ tests/ui/deny_elided_lifetimes.stderr | 15 +++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 tests/ui/deny_elided_lifetimes.rs create mode 100644 tests/ui/deny_elided_lifetimes.stderr diff --git a/tests/ui/deny_elided_lifetimes.rs b/tests/ui/deny_elided_lifetimes.rs new file mode 100644 index 000000000..0ab3f750a --- /dev/null +++ b/tests/ui/deny_elided_lifetimes.rs @@ -0,0 +1,27 @@ +#![deny(elided_lifetimes_in_paths)] + +#[cxx::bridge] +mod ffi { + #[derive(PartialEq, PartialOrd, Hash)] + struct Struct<'a> { + reference: &'a i32, + } + + extern "Rust" { + type Rust<'a>; + } + + unsafe extern "C++" { + type Cpp<'a>; + + fn lifetime_named<'a>(s: &'a i32) -> UniquePtr>; + + fn lifetime_underscore(s: &i32) -> UniquePtr>; + + fn lifetime_elided(s: &i32) -> UniquePtr; + } +} + +pub struct Rust<'a>(&'a i32); + +fn main() {} diff --git a/tests/ui/deny_elided_lifetimes.stderr b/tests/ui/deny_elided_lifetimes.stderr new file mode 100644 index 000000000..8b965af36 --- /dev/null +++ b/tests/ui/deny_elided_lifetimes.stderr @@ -0,0 +1,15 @@ +error: hidden lifetime parameters in types are deprecated + --> tests/ui/deny_elided_lifetimes.rs:21:50 + | +21 | fn lifetime_elided(s: &i32) -> UniquePtr; + | ^^^ expected named lifetime parameter + | +note: the lint level is defined here + --> tests/ui/deny_elided_lifetimes.rs:1:9 + | +1 | #![deny(elided_lifetimes_in_paths)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider using the `'_` lifetime + | +21 | fn lifetime_elided(s: &i32) -> UniquePtr>; + | ~~~~~~~