Skip to content

Fill in elided lifetimes in generated code #981

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions macro/src/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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),
Expand Down
53 changes: 32 additions & 21 deletions macro/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}

Expand All @@ -70,15 +70,15 @@ 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) => {
expanded.extend(expand_cxx_function_shim(efn, 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) => {
Expand Down Expand Up @@ -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 {
Expand All @@ -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)
}
Expand All @@ -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)
}
Expand All @@ -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)
}
Expand All @@ -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)
}
Expand All @@ -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)
}
Expand All @@ -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)
}
Expand All @@ -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))
}
Expand Down Expand Up @@ -396,10 +397,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.
Expand All @@ -424,7 +428,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
};
}
}
Expand Down Expand Up @@ -833,21 +837,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<T: ?::cxx::core::marker::Sized + #unpin>() {}
__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;
Expand All @@ -868,6 +876,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)]
Expand All @@ -877,12 +888,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()
}
}
}
Expand Down Expand Up @@ -1393,7 +1404,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)]
Expand Down Expand Up @@ -1485,7 +1496,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)]
Expand Down Expand Up @@ -1545,7 +1556,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)]
Expand Down Expand Up @@ -1660,7 +1671,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)]
Expand Down
32 changes: 30 additions & 2 deletions macro/src/generics.rs
Original file line number Diff line number Diff line change
@@ -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>,
Expand Down Expand Up @@ -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);
}
}
27 changes: 27 additions & 0 deletions tests/ui/deny_elided_lifetimes.rs
Original file line number Diff line number Diff line change
@@ -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<Cpp<'a>>;

fn lifetime_underscore(s: &i32) -> UniquePtr<Cpp<'_>>;

fn lifetime_elided(s: &i32) -> UniquePtr<Cpp>;
}
}

pub struct Rust<'a>(&'a i32);

fn main() {}
15 changes: 15 additions & 0 deletions tests/ui/deny_elided_lifetimes.stderr
Original file line number Diff line number Diff line change
@@ -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<Cpp>;
| ^^^ 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<Cpp<'_>>;
| ~~~~~~~