Skip to content

Commit e0f06c7

Browse files
SilensAngelusNexemilio
authored andcommitted
Generate fields as non-pub if they would be access restricted in C++.
1 parent 5177889 commit e0f06c7

File tree

8 files changed

+684
-26
lines changed

8 files changed

+684
-26
lines changed

src/clang.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,15 @@ impl Cursor {
632632
unsafe { clang_getCXXAccessSpecifier(self.x) }
633633
}
634634

635+
/// Is the cursor's referrent publically accessible in C++?
636+
///
637+
/// Returns true if self.access_specifier() is `CX_CXXPublic` or
638+
/// `CX_CXXInvalidAccessSpecifier`.
639+
pub fn public_accessible(&self) -> bool {
640+
let access = self.access_specifier();
641+
access == CX_CXXPublic || access == CX_CXXInvalidAccessSpecifier
642+
}
643+
635644
/// Is this cursor's referent a field declaration that is marked as
636645
/// `mutable`?
637646
pub fn is_mutable_field(&self) -> bool {

src/codegen/mod.rs

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1271,10 +1271,11 @@ impl<'a> FieldCodegen<'a> for FieldData {
12711271
}
12721272
}
12731273

1274-
let is_private = self
1275-
.annotations()
1276-
.private_fields()
1277-
.unwrap_or(fields_should_be_private);
1274+
let is_private = (!self.is_public() &&
1275+
ctx.options().respect_cxx_access_specs) ||
1276+
self.annotations()
1277+
.private_fields()
1278+
.unwrap_or(fields_should_be_private);
12781279

12791280
let accessor_kind =
12801281
self.annotations().accessor_kind().unwrap_or(accessor_kind);
@@ -1395,6 +1396,17 @@ impl Bitfield {
13951396
}
13961397
}
13971398

1399+
fn access_specifier(
1400+
ctx: &BindgenContext,
1401+
is_pub: bool,
1402+
) -> proc_macro2::TokenStream {
1403+
if is_pub || !ctx.options().respect_cxx_access_specs {
1404+
quote! { pub }
1405+
} else {
1406+
quote! {}
1407+
}
1408+
}
1409+
13981410
impl<'a> FieldCodegen<'a> for BitfieldUnit {
13991411
type Extra = ();
14001412

@@ -1455,11 +1467,6 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
14551467
let unit_field_name = format!("_bitfield_{}", self.nth());
14561468
let unit_field_ident = ctx.rust_ident(&unit_field_name);
14571469

1458-
let field = quote! {
1459-
pub #unit_field_ident : #field_ty ,
1460-
};
1461-
fields.extend(Some(field));
1462-
14631470
let ctor_name = self.ctor_name();
14641471
let mut ctor_params = vec![];
14651472
let mut ctor_impl = quote! {};
@@ -1468,6 +1475,7 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
14681475
// implement AsRef<[u8]> / AsMut<[u8]> / etc.
14691476
let mut generate_ctor = layout.size <= RUST_DERIVE_IN_ARRAY_LIMIT;
14701477

1478+
let mut access_spec = !fields_should_be_private;
14711479
for bf in self.bitfields() {
14721480
// Codegen not allowed for anonymous bitfields
14731481
if bf.name().is_none() {
@@ -1478,6 +1486,7 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
14781486
continue;
14791487
}
14801488

1489+
access_spec &= bf.is_public();
14811490
let mut bitfield_representable_as_int = true;
14821491

14831492
bf.codegen(
@@ -1511,10 +1520,17 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
15111520
ctor_impl = bf.extend_ctor_impl(ctx, param_name, ctor_impl);
15121521
}
15131522

1523+
let access_spec = access_specifier(ctx, access_spec);
1524+
1525+
let field = quote! {
1526+
#access_spec #unit_field_ident : #field_ty ,
1527+
};
1528+
fields.extend(Some(field));
1529+
15141530
if generate_ctor {
15151531
methods.extend(Some(quote! {
15161532
#[inline]
1517-
pub fn #ctor_name ( #( #ctor_params ),* ) -> #unit_field_ty {
1533+
#access_spec fn #ctor_name ( #( #ctor_params ),* ) -> #unit_field_ty {
15181534
let mut __bindgen_bitfield_unit: #unit_field_ty = Default::default();
15191535
#ctor_impl
15201536
__bindgen_bitfield_unit
@@ -1550,7 +1566,7 @@ impl<'a> FieldCodegen<'a> for Bitfield {
15501566
fn codegen<F, M>(
15511567
&self,
15521568
ctx: &BindgenContext,
1553-
_fields_should_be_private: bool,
1569+
fields_should_be_private: bool,
15541570
_codegen_depth: usize,
15551571
_accessor_kind: FieldAccessorKind,
15561572
parent: &CompInfo,
@@ -1590,13 +1606,16 @@ impl<'a> FieldCodegen<'a> for Bitfield {
15901606
bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item);
15911607

15921608
let offset = self.offset_into_unit();
1593-
15941609
let width = self.width() as u8;
1610+
let access_spec = access_specifier(
1611+
ctx,
1612+
self.is_public() && !fields_should_be_private,
1613+
);
15951614

15961615
if parent.is_union() && !parent.can_be_rust_union(ctx) {
15971616
methods.extend(Some(quote! {
15981617
#[inline]
1599-
pub fn #getter_name(&self) -> #bitfield_ty {
1618+
#access_spec fn #getter_name(&self) -> #bitfield_ty {
16001619
unsafe {
16011620
::#prefix::mem::transmute(
16021621
self.#unit_field_ident.as_ref().get(#offset, #width)
@@ -1606,7 +1625,7 @@ impl<'a> FieldCodegen<'a> for Bitfield {
16061625
}
16071626

16081627
#[inline]
1609-
pub fn #setter_name(&mut self, val: #bitfield_ty) {
1628+
#access_spec fn #setter_name(&mut self, val: #bitfield_ty) {
16101629
unsafe {
16111630
let val: #bitfield_int_ty = ::#prefix::mem::transmute(val);
16121631
self.#unit_field_ident.as_mut().set(
@@ -1620,7 +1639,7 @@ impl<'a> FieldCodegen<'a> for Bitfield {
16201639
} else {
16211640
methods.extend(Some(quote! {
16221641
#[inline]
1623-
pub fn #getter_name(&self) -> #bitfield_ty {
1642+
#access_spec fn #getter_name(&self) -> #bitfield_ty {
16241643
unsafe {
16251644
::#prefix::mem::transmute(
16261645
self.#unit_field_ident.get(#offset, #width)
@@ -1630,7 +1649,7 @@ impl<'a> FieldCodegen<'a> for Bitfield {
16301649
}
16311650

16321651
#[inline]
1633-
pub fn #setter_name(&mut self, val: #bitfield_ty) {
1652+
#access_spec fn #setter_name(&mut self, val: #bitfield_ty) {
16341653
unsafe {
16351654
let val: #bitfield_int_ty = ::#prefix::mem::transmute(val);
16361655
self.#unit_field_ident.set(
@@ -1717,8 +1736,9 @@ impl CodeGenerator for CompInfo {
17171736

17181737
struct_layout.saw_base(inner_item.expect_type());
17191738

1739+
let access_spec = access_specifier(ctx, base.is_public());
17201740
fields.push(quote! {
1721-
pub #field_name: #inner,
1741+
#access_spec #field_name: #inner,
17221742
});
17231743
}
17241744
}

src/ir/comp.rs

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,9 @@ pub trait FieldMethods {
148148
/// If this is a bitfield, how many bits does it need?
149149
fn bitfield_width(&self) -> Option<u32>;
150150

151+
/// Is this feild declared public?
152+
fn is_public(&self) -> bool;
153+
151154
/// Get the annotations for this field.
152155
fn annotations(&self) -> &Annotations;
153156

@@ -412,6 +415,10 @@ impl FieldMethods for Bitfield {
412415
self.data.bitfield_width()
413416
}
414417

418+
fn is_public(&self) -> bool {
419+
self.data.is_public()
420+
}
421+
415422
fn annotations(&self) -> &Annotations {
416423
self.data.annotations()
417424
}
@@ -436,6 +443,7 @@ impl RawField {
436443
comment: Option<String>,
437444
annotations: Option<Annotations>,
438445
bitfield_width: Option<u32>,
446+
public: bool,
439447
offset: Option<usize>,
440448
) -> RawField {
441449
RawField(FieldData {
@@ -444,6 +452,7 @@ impl RawField {
444452
comment,
445453
annotations: annotations.unwrap_or_default(),
446454
bitfield_width,
455+
public,
447456
offset,
448457
})
449458
}
@@ -466,6 +475,10 @@ impl FieldMethods for RawField {
466475
self.0.bitfield_width()
467476
}
468477

478+
fn is_public(&self) -> bool {
479+
self.0.is_public()
480+
}
481+
469482
fn annotations(&self) -> &Annotations {
470483
self.0.annotations()
471484
}
@@ -878,6 +891,9 @@ pub struct FieldData {
878891
/// If this field is a bitfield, and how many bits does it contain if it is.
879892
bitfield_width: Option<u32>,
880893

894+
/// If the C++ field is declared `public`
895+
public: bool,
896+
881897
/// The offset of the field (in bits)
882898
offset: Option<usize>,
883899
}
@@ -899,6 +915,10 @@ impl FieldMethods for FieldData {
899915
self.bitfield_width
900916
}
901917

918+
fn is_public(&self) -> bool {
919+
self.public
920+
}
921+
902922
fn annotations(&self) -> &Annotations {
903923
&self.annotations
904924
}
@@ -934,6 +954,8 @@ pub struct Base {
934954
pub kind: BaseKind,
935955
/// Name of the field in which this base should be stored.
936956
pub field_name: String,
957+
/// Whether this base is inherited from publically.
958+
pub is_pub: bool,
937959
}
938960

939961
impl Base {
@@ -961,6 +983,11 @@ impl Base {
961983

962984
true
963985
}
986+
987+
/// Whether this base is inherited from publically.
988+
pub fn is_public(&self) -> bool {
989+
self.is_pub
990+
}
964991
}
965992

966993
/// A compound type.
@@ -1230,7 +1257,7 @@ impl CompInfo {
12301257
let mut maybe_anonymous_struct_field = None;
12311258
cursor.visit(|cur| {
12321259
if cur.kind() != CXCursor_FieldDecl {
1233-
if let Some((ty, clang_ty, offset)) =
1260+
if let Some((ty, clang_ty, public, offset)) =
12341261
maybe_anonymous_struct_field.take()
12351262
{
12361263
if cur.kind() == CXCursor_TypedefDecl &&
@@ -1242,16 +1269,17 @@ impl CompInfo {
12421269
// anonymous field. Detect that case here, and do
12431270
// nothing.
12441271
} else {
1245-
let field =
1246-
RawField::new(None, ty, None, None, None, offset);
1272+
let field = RawField::new(
1273+
None, ty, None, None, None, public, offset,
1274+
);
12471275
ci.fields.append_raw_field(field);
12481276
}
12491277
}
12501278
}
12511279

12521280
match cur.kind() {
12531281
CXCursor_FieldDecl => {
1254-
if let Some((ty, clang_ty, offset)) =
1282+
if let Some((ty, clang_ty, public, offset)) =
12551283
maybe_anonymous_struct_field.take()
12561284
{
12571285
let mut used = false;
@@ -1261,9 +1289,10 @@ impl CompInfo {
12611289
}
12621290
CXChildVisit_Continue
12631291
});
1292+
12641293
if !used {
12651294
let field = RawField::new(
1266-
None, ty, None, None, None, offset,
1295+
None, ty, None, None, None, public, offset,
12671296
);
12681297
ci.fields.append_raw_field(field);
12691298
}
@@ -1280,6 +1309,7 @@ impl CompInfo {
12801309
let comment = cur.raw_comment();
12811310
let annotations = Annotations::new(&cur);
12821311
let name = cur.spelling();
1312+
let is_public = cur.public_accessible();
12831313
let offset = cur.offset_of_field().ok();
12841314

12851315
// Name can be empty if there are bitfields, for example,
@@ -1297,6 +1327,7 @@ impl CompInfo {
12971327
comment,
12981328
annotations,
12991329
bit_width,
1330+
is_public,
13001331
offset,
13011332
);
13021333
ci.fields.append_raw_field(field);
@@ -1353,9 +1384,11 @@ impl CompInfo {
13531384
cur.kind() != CXCursor_EnumDecl
13541385
{
13551386
let ty = cur.cur_type();
1387+
let public = cur.public_accessible();
13561388
let offset = cur.offset_of_field().ok();
1389+
13571390
maybe_anonymous_struct_field =
1358-
Some((inner, ty, offset));
1391+
Some((inner, ty, public, offset));
13591392
}
13601393
}
13611394
CXCursor_PackedAttr => {
@@ -1388,6 +1421,8 @@ impl CompInfo {
13881421
ty: type_id,
13891422
kind,
13901423
field_name,
1424+
is_pub: cur.access_specifier() ==
1425+
clang_sys::CX_CXXPublic,
13911426
});
13921427
}
13931428
CXCursor_Constructor | CXCursor_Destructor |
@@ -1503,8 +1538,9 @@ impl CompInfo {
15031538
CXChildVisit_Continue
15041539
});
15051540

1506-
if let Some((ty, _, offset)) = maybe_anonymous_struct_field {
1507-
let field = RawField::new(None, ty, None, None, None, offset);
1541+
if let Some((ty, _, public, offset)) = maybe_anonymous_struct_field {
1542+
let field =
1543+
RawField::new(None, ty, None, None, None, public, offset);
15081544
ci.fields.append_raw_field(field);
15091545
}
15101546

src/lib.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,10 @@ impl Builder {
545545
output_vector.push(name.clone());
546546
}
547547

548+
if self.options.respect_cxx_access_specs {
549+
output_vector.push("--respect-cxx-access-specs".into());
550+
}
551+
548552
// Add clang arguments
549553

550554
output_vector.push("--".into());
@@ -1518,6 +1522,12 @@ impl Builder {
15181522
self.options.dynamic_library_name = Some(dynamic_library_name.into());
15191523
self
15201524
}
1525+
1526+
/// Generate bindings as `pub` only if the bound item is publically accessible by C++.
1527+
pub fn respect_cxx_access_specs(mut self, doit: bool) -> Self {
1528+
self.options.respect_cxx_access_specs = doit;
1529+
self
1530+
}
15211531
}
15221532

15231533
/// Configuration options for generated bindings.
@@ -1805,6 +1815,10 @@ struct BindgenOptions {
18051815
/// The name of the dynamic library (if we are generating bindings for a shared library). If
18061816
/// this is None, no dynamic bindings are created.
18071817
dynamic_library_name: Option<String>,
1818+
1819+
/// Only make generated bindings `pub` if the items would be publically accessible
1820+
/// by C++.
1821+
respect_cxx_access_specs: bool,
18081822
}
18091823

18101824
/// TODO(emilio): This is sort of a lie (see the error message that results from
@@ -1941,6 +1955,7 @@ impl Default for BindgenOptions {
19411955
array_pointers_in_arguments: false,
19421956
wasm_import_module_name: None,
19431957
dynamic_library_name: None,
1958+
respect_cxx_access_specs: false,
19441959
}
19451960
}
19461961
}

0 commit comments

Comments
 (0)