Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ generate_function = { path = "../../../../cargo/rs_bindings_from_cc/generate_bin
generate_function_thunk = { path = "../../../../cargo/rs_bindings_from_cc/generate_bindings/generate_function_thunk", package = "rs_bindings_from_cc_generate_function_thunk"}
generate_struct_and_union = { path = "../../../../cargo/rs_bindings_from_cc/generate_bindings/generate_struct_and_union", package = "rs_bindings_from_cc_generate_struct_and_union"}
has_bindings = { path = "../../../../cargo/rs_bindings_from_cc/generate_bindings/has_bindings", package = "rs_bindings_from_cc_has_bindings"}
lifetime_defaults_transform = { path = "../../../../cargo/rs_bindings_from_cc/generate_bindings/lifetime_defaults_transform", package = "rs_bindings_from_cc_lifetime_defaults_transform"}
rs_type_kind = { path = "../../../../cargo/rs_bindings_from_cc/generate_bindings/rs_type_kind", package = "rs_bindings_from_cc_rs_type_kind"}
arc_anyhow = { path = "../../../../cargo/common/arc_anyhow"}
code_gen_utils = { path = "../../../../cargo/common/code_gen_utils"}
Expand Down
1 change: 1 addition & 0 deletions rs_bindings_from_cc/generate_bindings/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ rust_library(
":generate_function_thunk",
":generate_struct_and_union",
":has_bindings",
":lifetime_defaults_transform",
":rs_type_kind",
"//common:arc_anyhow",
"//common:code_gen_utils",
Expand Down
1 change: 1 addition & 0 deletions rs_bindings_from_cc/generate_bindings/database/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub struct CodegenFunctions {
pub generate_enum: fn(&BindingsGenerator, Rc<Enum>) -> Result<ApiSnippets>,
pub generate_item: fn(&BindingsGenerator, ir::Item) -> Result<ApiSnippets>,
pub generate_record: fn(&BindingsGenerator, Rc<Record>) -> Result<ApiSnippets>,
pub decl_lifetime_arity: fn(&BindingsGenerator, ir::ItemId) -> Result<usize>,
}

memoized::query_group! {
Expand Down
32 changes: 29 additions & 3 deletions rs_bindings_from_cc/generate_bindings/database/rs_snippet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
use crate::code_snippet::{Feature, Visibility};
use crate::BindingsGenerator;
use arc_anyhow::{anyhow, Result};
use code_gen_utils::make_rs_ident;
use code_gen_utils::NamespaceQualifier;
use code_gen_utils::{make_rs_ident, make_rs_lifetime_ident};
use crubit_feature::CrubitFeature;
use error_report::{bail, ensure};
use flagset::FlagSet;
Expand Down Expand Up @@ -487,6 +487,7 @@ pub enum RsTypeKind {
/// If this record is an instantiation of a `UniformReprTemplateType`, this will be set.
uniform_repr_template_type: Option<Rc<UniformReprTemplateType>>,
owned_ptr_type: Option<Rc<str>>,
lifetimes: Vec<Lifetime>,
},
Enum {
enum_: Rc<Enum>,
Expand Down Expand Up @@ -845,6 +846,7 @@ impl RsTypeKind {
owned_ptr_type: record.owned_ptr_type.clone(),
record,
crate_path,
lifetimes: lifetimes.to_vec(),
})
}

Expand Down Expand Up @@ -1716,6 +1718,14 @@ impl PrimitiveName {
}
}

/// Detect whether a `Record` is the projection of `std::string_view`, as we special-case this.
fn record_is_raw_string_view(record: &ir::Record) -> bool {
matches!(
record.template_specialization,
Some(TemplateSpecialization { kind: TemplateSpecializationKind::StdStringView, .. })
) && record.rs_name.identifier.as_ref() == "raw_string_view"
}

impl RsTypeKind {
pub fn to_token_stream<'a>(
&self,
Expand Down Expand Up @@ -1779,12 +1789,28 @@ impl RsTypeKind {
crate_path,
uniform_repr_template_type,
owned_ptr_type: _,
lifetimes,
} => {
if let Some(generic_monomorphization) = uniform_repr_template_type {
return generic_monomorphization.to_token_stream(&db);
}
let ident = make_rs_ident(record.rs_name.identifier.as_ref());
quote! { #crate_path #ident }
let arity = (db.codegen_functions().decl_lifetime_arity)(&*db, record.id()).expect("RsTypeKind::to_token_stream: can't determine lifetime arity");
if arity == 0 || lifetimes.len() == arity || record_is_raw_string_view(record) {
// Use the safe projection.
let lts = if lifetimes.is_empty() {
quote! {}
} else {
quote! { <#( #lifetimes ),* > }
};
let ident = make_rs_ident(record.rs_name.identifier.as_ref());
quote! { #crate_path #ident #lts }
} else {
// Until we can get unsafe binders, the unsafe projection of a type with
// lifetime parameters is that type instantiated at all 'static.
let statics = std::iter::repeat_n(make_rs_lifetime_ident("static"), arity);
let ident = make_rs_ident(record.rs_name.identifier.as_ref());
quote! { #crate_path #ident <#( #statics ),* > }
}
}
RsTypeKind::Enum { enum_, crate_path } => {
let ident = make_rs_ident(&enum_.rs_name.identifier);
Expand Down
1 change: 1 addition & 0 deletions rs_bindings_from_cc/generate_bindings/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ pub fn new_database<'db>(
generate_enum: generate_enum::generate_enum,
generate_item,
generate_record: generate_struct_and_union::generate_record,
decl_lifetime_arity: lifetime_defaults_transform::decl_lifetime_arity,
},
rs_type_kind_safety,
record_field_safety,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,24 @@ pub struct BindingContext {
/// All variable names we've seen.
pub names: HashSet<Rc<str>>,
}
fn lifetime_arity(_db: &BindingsGenerator, ty: &CcType) -> Result<usize> {
fn lifetime_arity(db: &BindingsGenerator, ty: &CcType) -> Result<usize> {
// TODO(b/454627672): Support other types.
match &ty.variant {
CcTypeVariant::Pointer(_) => Ok(1),
CcTypeVariant::Primitive(_) => Ok(0),
CcTypeVariant::FuncPointer { .. } => {
bail!("TODO(b/454627672): function pointer returns are unsupported")
}
CcTypeVariant::Decl(_id) => bail!("TODO(b/454627672): decl returns are unsupported"),
CcTypeVariant::Decl(id) => decl_lifetime_arity(db, *id),
CcTypeVariant::Error(msg) => bail!("encountered error type: {:?}", msg),
}
}

fn record_lifetime_arity(db: &BindingsGenerator, rc: &Record) -> Result<usize, arc_anyhow::Error> {
// TODO(zarko): Handle the effects of [[lifetimebound]] et al on arity.
Ok(rc.lifetime_inputs.len())
}

fn decl_lifetime_arity_impl(
db: &BindingsGenerator,
item_id: ir::ItemId,
Expand All @@ -63,7 +68,38 @@ fn decl_lifetime_arity_impl(
{
Ok(1)
}
_ => bail!("Unexpected item found in type position: {:?}", item.cc_name_as_str()),
Item::TypeAlias(_ta) => {
bail!("Type aliases unhandled for lifetimes: {:?}", item.cc_name_as_str())
}
Item::Record(rc) => record_lifetime_arity(db, rc),
Item::IncompleteRecord(_) => {
bail!("Incomplete records unhandled for lifetimes: {:?}", item.cc_name_as_str())
}
Item::Enum(_ec) => bail!("Enums unhandled for lifetimes: {:?}", item.cc_name_as_str()),
Item::ExistingRustType(_ec) => {
bail!("Existing Rust types unhandled for lifetimes: {:?}", item.cc_name_as_str())
}
Item::Func(_) => {
bail!("Unexpected function found in type position: {:?}", item.cc_name_as_str())
}
Item::Comment(_) => {
bail!("Unexpected comment found in type position: {:?}", item.cc_name_as_str())
}
Item::Namespace(_) => {
bail!("Unexpected namespace found in type position: {:?}", item.cc_name_as_str())
}
Item::UseMod(_) => {
bail!("Unexpected UseMod found in type position: {:?}", item.cc_name_as_str())
}
Item::GlobalVar(_) => {
bail!("Unexpected global var found in type position: {:?}", item.cc_name_as_str())
}
Item::Constant(_) => {
bail!("Unexpected const found in type position: {:?}", item.cc_name_as_str())
}
Item::UnsupportedItem(_) => {
bail!("Unexpected unsupported item found in type position: {:?}", item.cc_name_as_str())
}
}
}

Expand Down Expand Up @@ -314,6 +350,9 @@ impl<'a, 'db> LifetimeDefaults<'a, 'db> {
.get_or_push_new_binding(l, |name| new_bindings.push(name.clone()))
})
.collect();
if new_ty.explicit_lifetimes.iter().any(|l| l.as_ref() == "unknown") {
new_ty.explicit_lifetimes.clear();
}
return Ok(new_ty);
}
// If there is no viable inferred lifetime, there is nothing to do.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,30 @@ fn test_lifetimebound_param_with_decl_type() -> Result<()> {
S f(S i1 [[clang::lifetimebound]]);
"#),
)?;
let dir = lifetime_defaults_transform_ir(&ir);
assert!(dir.is_err());
let dir = lifetime_defaults_transform_ir(&ir)?;
assert_ir_matches!(
dir,
quote! {
Func {
cc_name: "f",
rs_name: "f", ...
return_type: CcType { ... explicit_lifetimes: [] ... }, ...
...
params: [
FuncParam {
type_: CcType { ... explicit_lifetimes: [] ... },
identifier: "i1", ...
...
clang_lifetimebound: true,
...
}
],
...
lifetime_inputs: [],
...
}
}
);
Ok(())
}

Expand Down Expand Up @@ -909,7 +931,7 @@ fn test_struct_binds_lifetime_param() -> Result<()> {
return_type: CcType { ... explicit_lifetimes: ["a"] ... }, ...
lifetime_params: [],
...
lifetime_inputs: ["__this"],
lifetime_inputs: ["__this", "__this_0"],
...
}
}
Expand Down Expand Up @@ -947,7 +969,7 @@ fn test_struct_shadows_unknown_lifetime_param() -> Result<()> {
return_type: CcType { ... explicit_lifetimes: ["unknown_0"] ... }, ...
lifetime_params: [],
...
lifetime_inputs: ["__this"],
lifetime_inputs: ["__this", "__this_0"],
...
}
}
Expand Down Expand Up @@ -985,7 +1007,7 @@ fn test_struct_does_not_shadow_unrelated_lifetime_param() -> Result<()> {
return_type: CcType { ... explicit_lifetimes: ["a"] ... }, ...
lifetime_params: [],
...
lifetime_inputs: ["__this", "a"],
lifetime_inputs: ["__this", "__this_0", "a"],
...
}
}
Expand Down Expand Up @@ -1023,7 +1045,7 @@ fn test_struct_renames_shadowed_lifetime_param_in_function() -> Result<()> {
return_type: CcType { ... explicit_lifetimes: ["a_0"] ... }, ...
lifetime_params: [],
...
lifetime_inputs: ["a_0", "__this"],
lifetime_inputs: ["a_0", "__this", "__this_0"],
...
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include "rs_bindings_from_cc/test/assume_lifetimes/simple_string_view.h"

SV sv_ident(SV s) { return s; }
SV sv_make_raw() { return SV{}; }
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,10 @@

struct LIFETIME_PARAMS("a") SV {};

// TODO(zarko): We should mark 'unknowns (or equivalent) as unsafe.
SV sv_ident(SV s);
SV $unknown sv_ident_unknown(SV $unknown s);
SV sv_ident_unknown_elided(SV $unknown s);
SV sv_make_raw();

#endif // THIRD_PARTY_CRUBIT_RS_BINDINGS_FROM_CC_TEST_ASSUME_LIFETIMES_SIMPLE_STRING_VIEW_H_
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,31 @@ extern "C" void __rust_thunk___ZN2SVC1Ev(struct SV* __this) {
crubit::construct_at(__this);
}

extern "C" void __rust_thunk___Z8sv_ident2SV(struct SV* __return,
struct SV* s) {
new (__return) auto(sv_ident(std::move(*s)));
}

static_assert((struct SV (*)(struct SV)) & ::sv_ident);

extern "C" void __rust_thunk___Z16sv_ident_unknown2SV(struct SV* __return,
struct SV* s) {
new (__return) auto(sv_ident_unknown(std::move(*s)));
}

static_assert((struct SV (*)(struct SV)) & ::sv_ident_unknown);

extern "C" void __rust_thunk___Z23sv_ident_unknown_elided2SV(
struct SV* __return, struct SV* s) {
new (__return) auto(sv_ident_unknown_elided(std::move(*s)));
}

static_assert((struct SV (*)(struct SV)) & ::sv_ident_unknown_elided);

extern "C" void __rust_thunk___Z11sv_make_rawv(struct SV* __return) {
new (__return) auto(sv_make_raw());
}

static_assert((struct SV (*)()) & ::sv_make_raw);

#pragma clang diagnostic pop
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,83 @@ impl<'a> Default for SV<'a> {
}
}

/// TODO(zarko): We should mark 'unknowns (or equivalent) as unsafe.
///
/// Generated from: rs_bindings_from_cc/test/assume_lifetimes/simple_string_view.h;l=13
#[inline(always)]
pub fn sv_ident<'s>(mut s: crate::SV<'s>) -> crate::SV<'s> {
unsafe {
let mut __return = ::core::mem::MaybeUninit::<crate::SV<'s>>::uninit();
crate::detail::__rust_thunk___Z8sv_ident2SV(
&raw mut __return as *mut ::core::ffi::c_void,
&mut s,
);
__return.assume_init()
}
}

/// Generated from: rs_bindings_from_cc/test/assume_lifetimes/simple_string_view.h;l=14
#[inline(always)]
pub fn sv_ident_unknown(mut s: crate::SV<'static>) -> crate::SV<'static> {
unsafe {
let mut __return = ::core::mem::MaybeUninit::<crate::SV<'static>>::uninit();
crate::detail::__rust_thunk___Z16sv_ident_unknown2SV(
&raw mut __return as *mut ::core::ffi::c_void,
&mut s,
);
__return.assume_init()
}
}

/// Generated from: rs_bindings_from_cc/test/assume_lifetimes/simple_string_view.h;l=15
#[inline(always)]
pub fn sv_ident_unknown_elided(mut s: crate::SV<'static>) -> crate::SV<'static> {
unsafe {
let mut __return = ::core::mem::MaybeUninit::<crate::SV<'static>>::uninit();
crate::detail::__rust_thunk___Z23sv_ident_unknown_elided2SV(
&raw mut __return as *mut ::core::ffi::c_void,
&mut s,
);
__return.assume_init()
}
}

/// Generated from: rs_bindings_from_cc/test/assume_lifetimes/simple_string_view.h;l=16
#[inline(always)]
pub fn sv_make_raw() -> crate::SV<'static> {
unsafe {
let mut __return = ::core::mem::MaybeUninit::<crate::SV<'static>>::uninit();
crate::detail::__rust_thunk___Z11sv_make_rawv(
&raw mut __return as *mut ::core::ffi::c_void,
);
__return.assume_init()
}
}

mod detail {
#[allow(unused_imports)]
use super::*;
unsafe extern "C" {
pub(crate) unsafe fn __rust_thunk___ZN2SVC1Ev(__this: *mut ::core::ffi::c_void);
pub(crate) unsafe fn __rust_thunk___Z8sv_ident2SV<'s>(
__return: *mut ::core::ffi::c_void,
s: &mut crate::SV<'s>,
);
pub(crate) unsafe fn __rust_thunk___Z16sv_ident_unknown2SV(
__return: *mut ::core::ffi::c_void,
s: &mut crate::SV<'static>,
);
pub(crate) unsafe fn __rust_thunk___Z23sv_ident_unknown_elided2SV(
__return: *mut ::core::ffi::c_void,
s: &mut crate::SV<'static>,
);
pub(crate) unsafe fn __rust_thunk___Z11sv_make_rawv(__return: *mut ::core::ffi::c_void);
}
}

const _: () = {
assert!(::core::mem::size_of::<crate::SV>() == 1);
assert!(::core::mem::align_of::<crate::SV>() == 1);
static_assertions::assert_impl_all!(crate::SV: Copy,Clone);
static_assertions::assert_not_impl_any!(crate::SV: Drop);
static_assertions::assert_impl_all!(crate::SV<'static>: Copy,Clone);
static_assertions::assert_not_impl_any!(crate::SV<'static>: Drop);
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@ use googletest::prelude::*;
#[gtest]
fn my_test() {
let sv: simple_string_view::SV<'_> = simple_string_view::SV::default();
let _sv_id = simple_string_view::sv_ident(sv);

let sv_raw = simple_string_view::sv_make_raw();
let _sv_raw_id = simple_string_view::sv_ident(sv_raw);
}
Loading
Loading