Skip to content

Commit 957e54b

Browse files
cramertjcopybara-github
authored andcommitted
Add support for references inside bridge types
Additionally, this CL: * adds an operator==/!= impl for SliceRef in order to simplify testing. * fixes a bug where substs in composable bridged types were lowered using the TypeLocation of the parent type rather than TypeLocation::NestedBridgable PiperOrigin-RevId: 872574800
1 parent d68f26c commit 957e54b

File tree

9 files changed

+279
-48
lines changed

9 files changed

+279
-48
lines changed

cc_bindings_from_rs/generate_bindings/format_type.rs

Lines changed: 57 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ pub fn format_cc_ident(db: &BindingsGenerator, ident: &str) -> Result<Ident> {
7272
}
7373
}
7474

75-
pub fn format_pointer_or_reference_ty_for_cc<'tcx>(
75+
fn format_pointer_or_reference_ty_for_cc<'tcx>(
7676
db: &BindingsGenerator<'tcx>,
7777
pointee: Ty<'tcx>,
7878
mutability: Mutability,
@@ -91,7 +91,7 @@ pub fn format_pointer_or_reference_ty_for_cc<'tcx>(
9191
Ok(CcSnippet { prereqs, tokens: quote! { #tokens #const_qualifier #pointer_sigil } })
9292
}
9393

94-
pub fn format_slice_ref_for_cc<'tcx>(
94+
fn format_slice_ref_for_cc<'tcx>(
9595
db: &BindingsGenerator<'tcx>,
9696
element_ty: Ty<'tcx>,
9797
mutability: rustc_middle::mir::Mutability,
@@ -118,11 +118,11 @@ pub fn format_slice_ref_for_cc<'tcx>(
118118
}
119119

120120
/// Returns a CcSnippet referencing `rs_std::StrRef` and its include path.
121-
pub fn format_str_ref_for_cc<'tcx>(db: &BindingsGenerator<'tcx>) -> CcSnippet<'tcx> {
121+
fn format_str_ref_for_cc<'tcx>(db: &BindingsGenerator<'tcx>) -> CcSnippet<'tcx> {
122122
CcSnippet::with_include(quote! { rs_std::StrRef }, db.support_header("rs_std/str_ref.h"))
123123
}
124124

125-
pub fn format_transparent_pointee_or_reference_for_cc<'tcx>(
125+
fn format_transparent_pointee_or_reference_for_cc<'tcx>(
126126
db: &BindingsGenerator<'tcx>,
127127
referent_ty: Ty<'tcx>,
128128
mutability: rustc_middle::mir::Mutability,
@@ -315,13 +315,15 @@ pub fn format_ty_for_cc<'tcx>(
315315
BridgedType::Composable(mut composable) => {
316316
// The existance of crubit_abi_type implies that the type can fully
317317
// composably bridge.
318-
319318
let mut tokens = composable.cpp_type.to_token_stream();
320-
321319
if !substs.is_empty() {
322320
let mut generic_types_tokens = Vec::with_capacity(substs.len());
323321
for subst in *substs {
324-
let snippet = format_ty_for_cc(db, subst.expect_ty(), location)?;
322+
let snippet = format_ty_for_cc(
323+
db,
324+
subst.expect_ty(),
325+
TypeLocation::NestedBridgeable,
326+
)?;
325327
generic_types_tokens
326328
.push(snippet.into_tokens(&mut composable.prereqs));
327329
}
@@ -562,7 +564,7 @@ pub fn format_ret_ty_for_cc<'tcx>(
562564
.with_context(|| format!("Error formatting function return type `{output_ty}`"))
563565
}
564566

565-
pub fn has_elided_region<'tcx>(tcx: TyCtxt<'tcx>, search_ty: ty::Ty<'tcx>) -> bool {
567+
pub(crate) fn has_elided_region<'tcx>(tcx: TyCtxt<'tcx>, search_ty: ty::Ty<'tcx>) -> bool {
566568
use core::ops::ControlFlow;
567569
use rustc_middle::ty::{Region, TyCtxt, TypeVisitor};
568570

@@ -637,7 +639,7 @@ fn try_ty_as_maybe_uninit<'tcx>(
637639
}
638640

639641
/// Format a supported `repr(transparent)` pointee type
640-
pub fn format_transparent_pointee<'tcx>(
642+
fn format_transparent_pointee<'tcx>(
641643
db: &BindingsGenerator<'tcx>,
642644
ty: Ty<'tcx>,
643645
) -> Result<TokenStream> {
@@ -762,12 +764,13 @@ pub fn format_ty_for_rs<'tcx>(db: &BindingsGenerator<'tcx>, ty: Ty<'tcx>) -> Res
762764
.map(|subst| match subst.kind() {
763765
ty::GenericArgKind::Type(ty) => db.format_ty_for_rs(ty),
764766
ty::GenericArgKind::Lifetime(region) => {
765-
assert_eq!(
766-
region.kind(),
767-
ty::RegionKind::ReStatic,
768-
"We should never format types with non-'static regions, as \
769-
thunks should first call `replace_all_regions_with_static`. {ty}",
770-
);
767+
if !region.is_static() {
768+
panic!(
769+
"We should never format types with non-'static regions, as \
770+
thunks should first call `replace_all_regions_with_static`. \
771+
Found type: `{ty}`."
772+
);
773+
}
771774
Ok(quote! { 'static })
772775
}
773776
ty::GenericArgKind::Const(_) => {
@@ -850,6 +853,7 @@ pub fn format_region_as_cc_lifetime<'tcx>(
850853
}
851854
}
852855

856+
#[track_caller]
853857
pub fn format_region_as_rs_lifetime<'tcx>(
854858
tcx: TyCtxt<'tcx>,
855859
region: ty::Region<'tcx>,
@@ -1014,21 +1018,27 @@ pub fn crubit_abi_type_from_ty<'tcx>(
10141018
}
10151019
// Do we need to confirm that pointee is layout compatible?
10161020
let rust_type = db.format_ty_for_rs(pointee)?;
1017-
let cpp_type_with_prereqs = db.format_ty_for_cc(pointee, TypeLocation::Other)?;
1021+
let CcSnippet { tokens: cpp_type, prereqs } =
1022+
db.format_ty_for_cc(pointee, TypeLocation::Other)?;
10181023

10191024
return Ok(CrubitAbiTypeWithCcPrereqs {
10201025
crubit_abi_type: CrubitAbiType::Ptr {
10211026
is_const: mutability.is_not(),
10221027
is_rust_slice,
10231028
rust_type,
1024-
cpp_type: cpp_type_with_prereqs.tokens,
1029+
cpp_type,
10251030
},
1026-
prereqs: cpp_type_with_prereqs.prereqs,
1031+
prereqs,
10271032
});
10281033
}
1029-
ty::TyKind::Ref(_region, _inner, _mutability) => {
1030-
// TODO(okabayashi): Support &str and &[T], and possibly other reference types.
1031-
bail!("Reference types are not yet supported in bridging");
1034+
ty::TyKind::Ref(_, _, _) => {
1035+
let rust_type = db.format_ty_for_rs(ty)?;
1036+
let CcSnippet { tokens: cpp_type, prereqs } =
1037+
db.format_ty_for_cc(ty, TypeLocation::Other)?;
1038+
return Ok(CrubitAbiTypeWithCcPrereqs {
1039+
crubit_abi_type: CrubitAbiType::Transmute { rust_type, cpp_type },
1040+
prereqs,
1041+
});
10321042
}
10331043
_ => bail!("Unsupported bridge type: {ty:?}"),
10341044
}))
@@ -1216,30 +1226,40 @@ pub fn is_bridged_type<'tcx>(
12161226
db: &BindingsGenerator<'tcx>,
12171227
ty: Ty<'tcx>,
12181228
) -> Result<Option<BridgedType<'tcx>>> {
1219-
match ty.kind() {
1220-
ty::TyKind::Ref(_, referent, _) if is_bridged_type(db, *referent)?.is_some() => {
1221-
if let ty::TyKind::Adt(adt, _) = referent.kind() {
1222-
if let Some(BridgedBuiltin::Option) = BridgedBuiltin::new(db, *adt) {
1223-
return Ok(None);
1229+
// The ABI of bridged types is lifetime-independent, and the Crubit thunks replace all
1230+
// lifetimes with static.
1231+
let ty = crate::generate_function_thunk::replace_all_regions_with_static(db.tcx(), ty);
1232+
1233+
match *ty.kind() {
1234+
ty::TyKind::Ref(_, referent, _) => {
1235+
if is_bridged_type(db, referent)?.is_some() {
1236+
if let ty::TyKind::Adt(adt, _) = referent.kind() {
1237+
if let Some(BridgedBuiltin::Option) = BridgedBuiltin::new(db, *adt) {
1238+
return Ok(None);
1239+
}
12241240
}
1241+
bail!(
1242+
"Can't format reference type `{ty}` because the referent is a bridged type. \
1243+
Passing bridged types by reference is not supported."
1244+
)
12251245
}
1226-
bail!(
1227-
"Can't format reference type `{ty}` because the referent is a bridged type. \
1228-
Passing bridged types by reference is not supported."
1229-
)
1246+
Ok(None)
12301247
}
1231-
ty::TyKind::RawPtr(pointee, _) if is_bridged_type(db, *pointee)?.is_some() => {
1232-
bail!(
1233-
"Can't format pointer type `{ty}` because the pointee is a bridged type. \
1234-
Passing bridged types by pointer is not supported."
1235-
)
1248+
ty::TyKind::RawPtr(pointee, _) => {
1249+
if is_bridged_type(db, pointee)?.is_some() {
1250+
bail!(
1251+
"Can't format pointer type `{ty}` because the pointee is a bridged type. \
1252+
Passing bridged types by pointer is not supported."
1253+
)
1254+
}
1255+
Ok(None)
12361256
}
12371257
ty::TyKind::Adt(adt, substs) => {
12381258
if let Some(bridged_type) = is_manually_annotated_bridged_adt(db, ty)? {
12391259
return Ok(Some(bridged_type));
12401260
}
12411261

1242-
if let Some(bridged_builtin) = BridgedBuiltin::new(db, *adt) {
1262+
if let Some(bridged_builtin) = BridgedBuiltin::new(db, adt) {
12431263
// The ADT is either a Result or an Option, which are composable bridged types.
12441264
let crubit_abi_type_with_cc_prereqs =
12451265
bridged_builtin.crubit_abi_type(db, substs)?;
@@ -1259,7 +1279,7 @@ pub fn is_bridged_type<'tcx>(
12591279
// The ADT does not need to be bridged, but check if it has generic types that
12601280
// need to be bridged e.g. Box<BridgedType> cannot be formated at
12611281
// the moment. If we encounter a type like this we return an error.
1262-
for subst in *substs {
1282+
for subst in substs {
12631283
if let Some(ty) = subst.as_type() {
12641284
if is_bridged_type(db, ty)?.is_some() {
12651285
bail!("Can't format ADT as it has a generic type `{ty}` that is a bridged type");

cc_bindings_from_rs/generate_bindings/generate_function_thunk.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -337,10 +337,7 @@ pub(crate) fn ident_or_opt_ident(i: &Option<rustc_span::Ident>) -> Option<&rustc
337337

338338
/// Returns an iterator which yields arbitrary unique names for the parameters
339339
/// of the function identified by `fn_def_id`.
340-
pub fn thunk_param_names(
341-
tcx: ty::TyCtxt<'_>,
342-
fn_def_id: DefId,
343-
) -> impl Iterator<Item = Ident> + '_ {
340+
fn thunk_param_names(tcx: ty::TyCtxt<'_>, fn_def_id: DefId) -> impl Iterator<Item = Ident> + '_ {
344341
tcx.fn_arg_idents(fn_def_id).iter().enumerate().map(|(i, ident)| {
345342
let Some(ident) = ident_or_opt_ident(ident) else {
346343
return format_ident!("__param_{i}");

cc_bindings_from_rs/test/bridging/composable/composable_bridging.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,18 @@ pub fn assert_some_some_5(x: Option<Option<i32>>) {
3030
assert_eq!(x, Some(Some(5)));
3131
}
3232

33+
pub fn option_slice_without_first(x: Option<&[i32]>) -> Option<&[i32]> {
34+
let (_first, rest) = x?.split_first()?;
35+
Some(rest)
36+
}
37+
38+
pub fn option_adds_one_to_ref(x: Option<&mut i32>) -> Option<&mut i32> {
39+
x.map(|x| {
40+
*x += 1;
41+
x
42+
})
43+
}
44+
3345
#[crubit_annotate::cpp_bridge(
3446
cpp_type = "std::optional",
3547
bridge_abi_cpp = "crubit::OptionalAbi",

cc_bindings_from_rs/test/bridging/composable/composable_bridging_test.cc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
namespace crubit {
1313
namespace {
1414

15+
using ::rs_std::SliceRef;
16+
1517
TEST(ComposableBridging, MaybeInt) {
1618
std::optional<int> maybe_int = composable_bridging::maybe_int();
1719
ASSERT_TRUE(maybe_int.has_value());
@@ -43,5 +45,24 @@ TEST(ComposableBridging, Parameters) {
4345
std::make_optional(std::make_optional(5)));
4446
}
4547

48+
TEST(ComposableBridging, NestedSlices) {
49+
using ::composable_bridging::option_slice_without_first;
50+
EXPECT_EQ(option_slice_without_first(std::nullopt), std::nullopt);
51+
EXPECT_EQ(option_slice_without_first(
52+
std::make_optional<SliceRef<const int>>({1, 2, 3})),
53+
std::make_optional<SliceRef<const int>>({2, 3}));
54+
}
55+
56+
TEST(ComposableBridging, NestedRefs) {
57+
using ::composable_bridging::option_adds_one_to_ref;
58+
EXPECT_EQ(option_adds_one_to_ref(std::nullopt), std::nullopt);
59+
int x = 5;
60+
std::optional<int* crubit_nonnull> y =
61+
option_adds_one_to_ref(std::make_optional(&x));
62+
ASSERT_TRUE(y.has_value());
63+
EXPECT_EQ(*y.value(), 6);
64+
EXPECT_EQ(x, 6);
65+
}
66+
4667
} // namespace
4768
} // namespace crubit

cc_bindings_from_rs/test/golden/composable_bridging.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,18 @@ pub fn option_increments(x: Option<i32>) -> Option<i32> {
2121
x.map(|x| x + 1)
2222
}
2323

24+
pub fn option_slice_without_first(x: Option<&[i32]>) -> Option<&[i32]> {
25+
let (_first, rest) = x?.split_first()?;
26+
Some(rest)
27+
}
28+
29+
pub fn option_adds_one_to_ref(x: Option<&mut i32>) -> Option<&mut i32> {
30+
x.map(|x| {
31+
*x += 1;
32+
x
33+
})
34+
}
35+
2436
///CRUBIT_ANNOTATE: cpp_type=std::optional
2537
///CRUBIT_ANNOTATE: bridge_abi_cpp=crubit::OptionalAbi
2638
///CRUBIT_ANNOTATE: bridge_abi_rust=MyOptionRustAbi

cc_bindings_from_rs/test/golden/composable_bridging_cc_api.h

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313

1414
#pragma clang diagnostic push
1515
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
16+
#include "support/annotations_internal.h"
1617
#include "support/bridge.h"
18+
#include "support/lifetime_annotations.h"
1719
#include "support/rs_std/slice_ref.h"
1820

1921
#include <cstdint>
@@ -23,27 +25,37 @@ namespace composable_bridging_rust {
2325

2426
// Error generating bindings for `composable_bridging_rust_golden::MyOptionRust`
2527
// defined at
26-
// cc_bindings_from_rs/test/golden/composable_bridging.rs;l=27:
28+
// cc_bindings_from_rs/test/golden/composable_bridging.rs;l=39:
2729
// Type bindings for composable_bridging_rust_golden::MyOptionRust suppressed
2830
// due to being mapped to an existing C++ type (std::optional)
2931

3032
// Error generating bindings for
3133
// `composable_bridging_rust_golden::MyOptionRustAbi` defined at
32-
// cc_bindings_from_rs/test/golden/composable_bridging.rs;l=38:
34+
// cc_bindings_from_rs/test/golden/composable_bridging.rs;l=50:
3335
// Generic types are not supported yet (b/259749095)
3436

3537
// Generated from:
36-
// cc_bindings_from_rs/test/golden/composable_bridging.rs;l=29
38+
// cc_bindings_from_rs/test/golden/composable_bridging.rs;l=41
3739
std::optional<std::int32_t> make_my_option_rust();
3840

3941
// Generated from:
40-
// cc_bindings_from_rs/test/golden/composable_bridging.rs;l=33
42+
// cc_bindings_from_rs/test/golden/composable_bridging.rs;l=45
4143
std::optional<rs_std::SliceRef<const std::int32_t>> maybe_int_slice();
4244

45+
// Generated from:
46+
// cc_bindings_from_rs/test/golden/composable_bridging.rs;l=29
47+
std::optional<std::int32_t* $(__anon1) crubit_nonnull> option_adds_one_to_ref(
48+
std::optional<std::int32_t* $(__anon1) crubit_nonnull> x);
49+
4350
// Generated from:
4451
// cc_bindings_from_rs/test/golden/composable_bridging.rs;l=20
4552
std::optional<std::int32_t> option_increments(std::optional<std::int32_t> x);
4653

54+
// Generated from:
55+
// cc_bindings_from_rs/test/golden/composable_bridging.rs;l=24
56+
std::optional<rs_std::SliceRef<const std::int32_t>> option_slice_without_first(
57+
std::optional<rs_std::SliceRef<const std::int32_t>> x);
58+
4759
// Generated from:
4860
// cc_bindings_from_rs/test/golden/composable_bridging.rs;l=12
4961
std::optional<std::int32_t> returns_no_int();
@@ -86,6 +98,33 @@ inline std::optional<rs_std::SliceRef<const std::int32_t>> maybe_int_slice() {
8698
__return_value_storage);
8799
}
88100

101+
namespace __crubit_internal {
102+
extern "C" void __crubit_thunk_option_uadds_uone_uto_uref(
103+
unsigned char*, unsigned char* __ret_ptr);
104+
}
105+
inline std::optional<std::int32_t* $(__anon1) crubit_nonnull>
106+
option_adds_one_to_ref(
107+
std::optional<std::int32_t* $(__anon1) crubit_nonnull> x) {
108+
unsigned char x_buffer[::crubit::OptionAbi<
109+
::crubit::TransmuteAbi<std::int32_t* $static crubit_nonnull>>::kSize];
110+
::crubit::internal::Encode<::crubit::OptionAbi<
111+
::crubit::TransmuteAbi<std::int32_t* $static crubit_nonnull>>>(
112+
::crubit::OptionAbi<
113+
::crubit::TransmuteAbi<std::int32_t* $static crubit_nonnull>>(
114+
::crubit::TransmuteAbi<std::int32_t* $static crubit_nonnull>()),
115+
x_buffer, x);
116+
unsigned char __return_value_storage[::crubit::OptionAbi<
117+
::crubit::TransmuteAbi<std::int32_t* $static crubit_nonnull>>::kSize];
118+
__crubit_internal::__crubit_thunk_option_uadds_uone_uto_uref(
119+
x_buffer, __return_value_storage);
120+
return ::crubit::internal::Decode<::crubit::OptionAbi<
121+
::crubit::TransmuteAbi<std::int32_t* $static crubit_nonnull>>>(
122+
::crubit::OptionAbi<
123+
::crubit::TransmuteAbi<std::int32_t* $static crubit_nonnull>>(
124+
::crubit::TransmuteAbi<std::int32_t* $static crubit_nonnull>()),
125+
__return_value_storage);
126+
}
127+
89128
namespace __crubit_internal {
90129
extern "C" void __crubit_thunk_option_uincrements(unsigned char*,
91130
unsigned char* __ret_ptr);
@@ -110,6 +149,33 @@ inline std::optional<std::int32_t> option_increments(
110149
__return_value_storage);
111150
}
112151

152+
namespace __crubit_internal {
153+
extern "C" void __crubit_thunk_option_uslice_uwithout_ufirst(
154+
unsigned char*, unsigned char* __ret_ptr);
155+
}
156+
inline std::optional<rs_std::SliceRef<const std::int32_t>>
157+
option_slice_without_first(
158+
std::optional<rs_std::SliceRef<const std::int32_t>> x) {
159+
unsigned char x_buffer[::crubit::OptionAbi<
160+
::crubit::TransmuteAbi<rs_std::SliceRef<const std::int32_t>>>::kSize];
161+
::crubit::internal::Encode<::crubit::OptionAbi<
162+
::crubit::TransmuteAbi<rs_std::SliceRef<const std::int32_t>>>>(
163+
::crubit::OptionAbi<
164+
::crubit::TransmuteAbi<rs_std::SliceRef<const std::int32_t>>>(
165+
::crubit::TransmuteAbi<rs_std::SliceRef<const std::int32_t>>()),
166+
x_buffer, x);
167+
unsigned char __return_value_storage[::crubit::OptionAbi<
168+
::crubit::TransmuteAbi<rs_std::SliceRef<const std::int32_t>>>::kSize];
169+
__crubit_internal::__crubit_thunk_option_uslice_uwithout_ufirst(
170+
x_buffer, __return_value_storage);
171+
return ::crubit::internal::Decode<::crubit::OptionAbi<
172+
::crubit::TransmuteAbi<rs_std::SliceRef<const std::int32_t>>>>(
173+
::crubit::OptionAbi<
174+
::crubit::TransmuteAbi<rs_std::SliceRef<const std::int32_t>>>(
175+
::crubit::TransmuteAbi<rs_std::SliceRef<const std::int32_t>>()),
176+
__return_value_storage);
177+
}
178+
113179
namespace __crubit_internal {
114180
extern "C" void __crubit_thunk_returns_uno_uint(unsigned char* __ret_ptr);
115181
}

0 commit comments

Comments
 (0)