Skip to content
Open
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
55 changes: 39 additions & 16 deletions cc_bindings_from_rs/generate_bindings/format_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,22 @@ fn format_pointer_or_reference_ty_for_cc<'tcx>(
pointee: Ty<'tcx>,
mutability: Mutability,
pointer_sigil: TokenStream,
is_reference: bool,
) -> Result<CcSnippet<'tcx>> {
let tcx = db.tcx();
let const_qualifier = match mutability {
Mutability::Mut => quote! {},
Mutability::Not => quote! { const },
};
if pointee.is_c_void(tcx) {
return Ok(CcSnippet { tokens: quote! { #const_qualifier void* }, ..Default::default() });
let mut prereqs = CcPrerequisites::default();
let tokens = if is_reference {
prereqs.includes.insert(db.support_header("annotations_internal.h"));
quote! { #const_qualifier void* crubit_nonnull }
} else {
quote! { #const_qualifier void #pointer_sigil }
};
return Ok(CcSnippet { tokens, prereqs });
}
let CcSnippet { tokens, mut prereqs } = db.format_ty_for_cc(pointee, TypeLocation::Other)?;
prereqs.move_defs_to_fwd_decls();
Expand Down Expand Up @@ -135,6 +143,7 @@ fn format_transparent_pointee_or_reference_for_cc<'tcx>(
referent_ty: Ty<'tcx>,
mutability: rustc_middle::mir::Mutability,
pointer_sigil: TokenStream,
is_reference: bool,
) -> Option<CcSnippet<'tcx>> {
let ty::TyKind::Adt(adt, substs) = referent_ty.kind() else {
return None;
Expand All @@ -147,7 +156,8 @@ fn format_transparent_pointee_or_reference_for_cc<'tcx>(
}

let referent = substs[0].expect_ty();
format_pointer_or_reference_ty_for_cc(db, referent, mutability, pointer_sigil).ok()
format_pointer_or_reference_ty_for_cc(db, referent, mutability, pointer_sigil, is_reference)
.ok()
}

fn format_legacy_bridged_type_with_placeholders<'tcx>(
Expand Down Expand Up @@ -380,6 +390,7 @@ pub fn format_ty_for_cc<'tcx>(
referent,
Mutability::Mut,
quote! { && },
/*is_reference=*/ true,
);
}
let def_id = adt.did();
Expand Down Expand Up @@ -504,17 +515,25 @@ pub fn format_ty_for_cc<'tcx>(
check_slice_layout(db.tcx(), ty);
return format_slice_ref_for_cc(db, *slice_ty, mutbl);
}
// Early return in case we handle a transparent pointer type.
if let Some(snippet) =
format_transparent_pointee_or_reference_for_cc(db, pointee_ty, mutbl, quote! { * })
{
return Ok(snippet);
}

format_pointer_or_reference_ty_for_cc(db, pointee_ty, mutbl, quote! { * })
let sigil = quote! { * crubit_nullability_unknown };
let mut snippet = if let Some(snippet) = format_transparent_pointee_or_reference_for_cc(
db,
pointee_ty,
mutbl,
sigil.clone(),
/*is_reference=*/ false,
) {
snippet
} else {
format_pointer_or_reference_ty_for_cc(
db, pointee_ty, mutbl, sigil, /*is_reference=*/ false,
)
.with_context(|| {
format!("Failed to format the pointee of the pointer type `{ty}`")
})?
};
snippet.prereqs.includes.insert(db.support_header("annotations_internal.h"));
snippet
}

ty::TyKind::Ref(region, referent, mutability) => {
Expand Down Expand Up @@ -559,17 +578,21 @@ pub fn format_ty_for_cc<'tcx>(
referent,
mutability,
ptr_or_ref_prefix.clone(),
/*is_reference=*/ true,
) {
snippet.prereqs += prereqs;
return Ok(snippet);
}

let tokens =
format_pointer_or_reference_ty_for_cc(db, referent, mutability, ptr_or_ref_prefix)
.with_context(|| {
format!("Failed to format the referent of the reference type `{ty}`")
})?
.into_tokens(&mut prereqs);
let tokens = format_pointer_or_reference_ty_for_cc(
db,
referent,
mutability,
ptr_or_ref_prefix,
/*is_reference=*/ true,
)
.with_context(|| format!("Failed to format the referent of the reference type `{ty}`"))?
.into_tokens(&mut prereqs);
CcSnippet { tokens, prereqs }
}
ty::TyKind::FnPtr(sig_tys, fn_header) => {
Expand Down
32 changes: 16 additions & 16 deletions cc_bindings_from_rs/generate_bindings/format_type_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,8 @@ fn test_format_ty_for_cc_successes() {
case!(rs: "SomeStruct", cc: "::rust_out::SomeStruct", includes: [], prereq_def: "SomeStruct"),
case!(rs: "SomeEnum", cc: "::rust_out::SomeEnum", includes: [], prereq_def: "SomeEnum"),
case!(rs: "SomeUnion", cc: "::rust_out::SomeUnion", includes: [], prereq_def: "SomeUnion"),
case!(rs: "*const i32", cc: "::std :: int32_t const *", includes: ["<cstdint>"]),
case!(rs: "*mut i32", cc: "::std :: int32_t *", includes: ["<cstdint>"]),
case!(rs: "*const i32", cc: "::std :: int32_t const * crubit_nullability_unknown", includes: ["<cstdint>", "<crubit/support/for/tests/annotations_internal.h>"]),
case!(rs: "*mut i32", cc: "::std :: int32_t * crubit_nullability_unknown", includes: ["<cstdint>", "<crubit/support/for/tests/annotations_internal.h>"]),
case!(
rs: "&'static i32",
cc: "::std :: int32_t const * $static crubit_nonnull",
Expand Down Expand Up @@ -219,20 +219,20 @@ fn test_format_ty_for_cc_successes() {
// `SomeStruct` is a `fwd_decls` prerequisite (not `defs` prerequisite):
case!(
rs: "*mut SomeStruct",
cc: "::rust_out::SomeStruct*",
includes: [],
cc: "::rust_out::SomeStruct * crubit_nullability_unknown",
includes: ["<crubit/support/for/tests/annotations_internal.h>"],
prereq_fwd_decl: "SomeStruct"
),
// Testing propagation of deeper/nested `fwd_decls`:
case!(
rs: "*mut *mut SomeStruct",
cc: ":: rust_out :: SomeStruct * *",
includes: [],
cc: ":: rust_out :: SomeStruct * crubit_nullability_unknown * crubit_nullability_unknown",
includes: ["<crubit/support/for/tests/annotations_internal.h>"],
prereq_fwd_decl: "SomeStruct"
),
// Testing propagation of `const` / `mut` qualifiers:
case!(rs: "*mut *const f32", cc: "float const * *"),
case!(rs: "*const *mut f32", cc: "float * const *"),
case!(rs: "*mut *const f32", cc: "float const * crubit_nullability_unknown * crubit_nullability_unknown", includes: ["<crubit/support/for/tests/annotations_internal.h>"]),
case!(rs: "*const *mut f32", cc: "float * crubit_nullability_unknown const * crubit_nullability_unknown", includes: ["<crubit/support/for/tests/annotations_internal.h>"]),
// Rust function pointers are non-nullable, so when function pointers are used as a
// parameter type (i.e. in `TypeLocation::FnParam`) then we can translate to
// generate a C++ function *reference*, rather than a C++ function *pointer*.
Expand All @@ -252,16 +252,16 @@ fn test_format_ty_for_cc_successes() {
// function *reference*.
case!(
rs: "*const extern \"C\" fn (f32, f32) -> f32",
cc: "crubit :: type_identity_t < float (float , float) > * const *",
includes: ["<crubit/support/for/tests/internal/cxx20_backports.h>"]
cc: "crubit :: type_identity_t < float (float , float) > * const * crubit_nullability_unknown",
includes: ["<crubit/support/for/tests/annotations_internal.h>", "<crubit/support/for/tests/internal/cxx20_backports.h>"]
),
// Extra parens/sugar are expected to be ignored:
case!(rs: "(bool)", cc: "bool"),
// References to MaybeUninit:
case!(
rs: "*const std::mem::MaybeUninit<i32>",
cc: "::std :: int32_t const *",
includes: ["<cstdint>"]
cc: "::std :: int32_t const * crubit_nullability_unknown",
includes: ["<cstdint>", "<crubit/support/for/tests/annotations_internal.h>"]
),
case!(
rs: "&mut std::mem::MaybeUninit<i32>",
Expand All @@ -286,13 +286,13 @@ fn test_format_ty_for_cc_successes() {
// TyKind::Array
case!(
rs: "*mut [i32; 42]",
cc: "::std::array < ::std::int32_t, 42> *",
includes: ["<array>", "<cstdint>"]
cc: "::std::array < ::std::int32_t, 42> * crubit_nullability_unknown",
includes: ["<array>", "<cstdint>", "<crubit/support/for/tests/annotations_internal.h>"]
),
case!(
rs: "*const [i32; 42]",
cc: "::std::array < ::std::int32_t, 42> const *",
includes: ["<array>", "<cstdint>"]
cc: "::std::array < ::std::int32_t, 42> const * crubit_nullability_unknown",
includes: ["<array>", "<cstdint>", "<crubit/support/for/tests/annotations_internal.h>"]
),
case!(
rs: "[i32; 42]",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,11 @@ fn test_generated_bindings_prereq_fwd_decls_for_ptr_param() {
// below also matters.
struct S;
...
void F(::rust_out::S const* __param_0);
void F(::rust_out::S const* crubit_nullability_unknown __param_0);
...
struct CRUBIT_INTERNAL_RUST_TYPE(...) alignas(...) [[clang::trivial_abi]] S final { ... }
...
inline void F(::rust_out::S const* __param_0) { ... }
inline void F(::rust_out::S const* crubit_nullability_unknown __param_0) { ... }
...
} // namespace rust_out
}
Expand Down Expand Up @@ -335,7 +335,7 @@ fn test_generated_bindings_prereq_fwd_decls_not_needed_inside_struct_definition(
bindings.cc_api,
quote! {
static ::rust_out::S create(); ...
union { ... ::rust_out::S const* field; }; ...
union { ... ::rust_out::S const* crubit_nullability_unknown field; }; ...
}
);
});
Expand Down Expand Up @@ -1292,7 +1292,7 @@ fn test_format_item_struct_with_custom_drop_and_no_default_and_clone(test_src: &
}
...
namespace __crubit_internal { // `pass_by_value` thunk decl
extern "C" void ...(::rust_out::TypeUnderTest* __ret_ptr);
extern "C" void ...(::rust_out::TypeUnderTest* crubit_nonnull __ret_ptr);
}
inline ::rust_out::TypeUnderTest TypeUnderTest::pass_by_value() {
crubit::Slot<::rust_out::TypeUnderTest> __return_value_ret_val_holder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1182,7 +1182,7 @@ fn test_format_item_fn_rust_abi_returning_struct_by_value() {
result.cc_details.tokens,
quote! {
namespace __crubit_internal {
extern "C" void ...(::std::int32_t, ::rust_out::S* __ret_ptr);
extern "C" void ...(::std::int32_t, ::rust_out::S* crubit_nonnull __ret_ptr);
}
...
inline ::rust_out::S create(::std::int32_t i) {
Expand Down
18 changes: 12 additions & 6 deletions cc_bindings_from_rs/generate_bindings/generate_function_thunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,30 +181,36 @@ pub fn generate_thunk_decl<'tcx>(
// We should centralize this logic so that the order exists in a singular location used by both
// places.
let thunk_ret_type = if is_constructor && is_bridged_layout_compat_type(db, sig_mid.output()) {
thunk_params.push(quote! { #main_api_ret_type* __ret_ptr });
prereqs.includes.insert(db.support_header("annotations_internal.h"));
thunk_params.push(quote! { #main_api_ret_type* crubit_nonnull __ret_ptr });
quote! { void }
} else if let Some(briging) = is_bridged_type(db, sig_mid.output())? {
match briging {
BridgedType::Legacy { .. } => {
thunk_params.push(quote! { #main_api_ret_type* __ret_ptr });
prereqs.includes.insert(db.support_header("annotations_internal.h"));
thunk_params.push(quote! { #main_api_ret_type* crubit_nonnull __ret_ptr });
quote! { void }
}
BridgedType::Composable(_) => {
thunk_params.push(quote! { unsigned char * __ret_ptr });
prereqs.includes.insert(db.support_header("annotations_internal.h"));
thunk_params.push(quote! { unsigned char * crubit_nonnull __ret_ptr });
quote! { void }
}
}
} else if is_c_abi_compatible_by_value(tcx, sig_mid.output()) {
main_api_ret_type
} else if let Some(tuple_abi) = tuple_c_abi_c_type(db, sig_mid.output()) {
thunk_params.push(quote! { #tuple_abi __ret_ptr });
prereqs.includes.insert(db.support_header("annotations_internal.h"));
thunk_params.push(quote! { #tuple_abi crubit_nonnull __ret_ptr });
quote! { void }
} else if let ty::TyKind::Array(inner_ty, _) = sig_mid.output().kind() {
let c_type = array_c_abi_c_type(db.tcx(), *inner_ty)?;
thunk_params.push(quote! { #c_type __ret_ptr });
prereqs.includes.insert(db.support_header("annotations_internal.h"));
thunk_params.push(quote! { #c_type crubit_nonnull __ret_ptr });
quote! { void }
} else {
thunk_params.push(quote! { #main_api_ret_type* __ret_ptr });
prereqs.includes.insert(db.support_header("annotations_internal.h"));
thunk_params.push(quote! { #main_api_ret_type* crubit_nonnull __ret_ptr });
quote! { void }
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ static_assert(
"Verify that ADT layout didn't change since this header got generated");
namespace __crubit_internal {
extern "C" void __crubit_thunk_default(
::aliasing_references::NonFreezeType* __ret_ptr);
::aliasing_references::NonFreezeType* crubit_nonnull __ret_ptr);
}
inline ::aliasing_references::NonFreezeType::NonFreezeType() {
__crubit_internal::__crubit_thunk_default(this);
Expand Down Expand Up @@ -167,7 +167,7 @@ static_assert(
"Verify that ADT layout didn't change since this header got generated");
namespace __crubit_internal {
extern "C" void __crubit_thunk_default(
::aliasing_references::SomeStruct* __ret_ptr);
::aliasing_references::SomeStruct* crubit_nonnull __ret_ptr);
}
inline ::aliasing_references::SomeStruct::SomeStruct() {
__crubit_internal::__crubit_thunk_default(this);
Expand Down
Loading