Skip to content

Commit 5d7c4d7

Browse files
author
bors-servo
authored
Auto merge of #20 - Manishearth:unsafe-field, r=Manishearth
Add support for 'unsafe fields' Needed for the next step of servo/servo#12521 These are fields which are private but have unsafe accessor functions. Since we generate bindings in a separate module, we can't touch private fields from other parts of the module (an alternative is to inject a footer with these private impls). `pub(restricted)` exists, but is not stable. r? @emilio
2 parents 8600b06 + 0fcf367 commit 5d7c4d7

File tree

10 files changed

+435
-12
lines changed

10 files changed

+435
-12
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ script:
4242
- cargo build --verbose --features llvm_stable
4343
- make test
4444
- git add -A
45+
- git diff @
4546
- git diff-index --quiet HEAD
4647

4748
notifications:

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ BINDGEN := ./target/debug/bindgen
99

1010
.PHONY: $(BINDGEN)
1111
$(BINDGEN):
12-
[ -f $@ ] || cargo build
12+
[ -f $@ ] || cargo build --features llvm_stable
1313

1414
.PHONY: test
1515
test: regen-tests

src/gen.rs

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use syntax::print::pprust::tts_to_string;
1919

2020
use super::BindgenOptions;
2121
use super::LinkType;
22+
use parser::Accessor;
2223
use types::*;
2324
use aster;
2425

@@ -840,6 +841,52 @@ fn comp_attrs(ctx: &GenCtx, ci: &CompInfo, name: &str, extra: &mut Vec<P<ast::It
840841
attrs
841842
}
842843

844+
fn gen_accessors(ctx: &mut GenCtx, name: &str, ty: &ast::Ty, accessor: Accessor,
845+
methods: &mut Vec<ast::ImplItem>) {
846+
if accessor == Accessor::None {
847+
return;
848+
}
849+
let ident = ctx.ext_cx.ident_of(&format!("{}", name));
850+
let mutable_getter_name = ctx.ext_cx.ident_of(&format!("get_{}_mut", name));
851+
let getter_name = ctx.ext_cx.ident_of(&format!("get_{}", name));
852+
let imp = match accessor {
853+
Accessor::Regular => quote_item!(&ctx.ext_cx,
854+
impl X {
855+
#[inline]
856+
pub fn $getter_name(&self) -> & $ty {
857+
& self.$ident
858+
}
859+
pub fn $mutable_getter_name(&mut self) -> &mut $ty {
860+
&mut self.$ident
861+
}
862+
}
863+
),
864+
Accessor::Unsafe => quote_item!(&ctx.ext_cx,
865+
impl X {
866+
#[inline]
867+
pub unsafe fn $getter_name(&self) -> & $ty {
868+
& self.$ident
869+
}
870+
pub unsafe fn $mutable_getter_name(&mut self) -> &mut $ty {
871+
&mut self.$ident
872+
}
873+
}
874+
),
875+
Accessor::Immutable => quote_item!(&ctx.ext_cx,
876+
impl X {
877+
#[inline]
878+
pub fn $getter_name(&self) -> & $ty {
879+
& self.$ident
880+
}
881+
}
882+
),
883+
_ => return
884+
};
885+
match imp.unwrap().node {
886+
ast::ItemKind::Impl(_, _, _, _, _, ref items) => methods.extend(items.clone()),
887+
_ => unreachable!()
888+
}
889+
}
843890

844891
fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item>> {
845892
let layout = ci.layout;
@@ -878,14 +925,15 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item>
878925
};
879926

880927
if let Some(ref base) = base_vftable {
881-
vffields.push(ast::StructField {
928+
let field = ast::StructField {
882929
span: ctx.span,
883930
vis: ast::Visibility::Public,
884931
ident: Some(ctx.ext_cx.ident_of("_base")),
885932
id: ast::DUMMY_NODE_ID,
886933
ty: P(mk_ty(ctx, false, &[base.clone()])),
887934
attrs: vec![],
888-
});
935+
};
936+
vffields.push(field);
889937
}
890938

891939
for vm in ci.vmethods.iter() {
@@ -1052,15 +1100,22 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item>
10521100
} else {
10531101
rust_ty
10541102
};
1055-
1056-
fields.push(ast::StructField {
1103+
let vis = if f.private {
1104+
ast::Visibility::Inherited
1105+
} else {
1106+
ast::Visibility::Public
1107+
};
1108+
gen_accessors(ctx, &f_name, &rust_ty, f.accessor, &mut methods);
1109+
let field = ast::StructField {
10571110
span: ctx.span,
10581111
ident: Some(ctx.ext_cx.ident_of(&f_name)),
1059-
vis: ast::Visibility::Public,
1112+
vis: vis,
10601113
id: ast::DUMMY_NODE_ID,
10611114
ty: rust_ty,
10621115
attrs: mk_doc_attr(ctx, &f.comment)
1063-
});
1116+
};
1117+
fields.push(field);
1118+
10641119
if bypass {
10651120
continue;
10661121
}

src/parser.rs

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global {
122122
CXCursor_ClassTemplate |
123123
CXCursor_ClassDecl |
124124
CXCursor_StructDecl => {
125+
let anno = Annotations::new(&cursor);
125126
let kind = if cursor.kind() == CXCursor_UnionDecl {
126127
CompKind::Union
127128
} else {
@@ -159,7 +160,7 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global {
159160
}
160161
};
161162

162-
let mut ci = CompInfo::new(spelling, ctx.current_module_id, filename, comment, kind, vec![], layout);
163+
let mut ci = CompInfo::new(spelling, ctx.current_module_id, filename, comment, kind, vec![], layout, anno);
163164
ci.parser_cursor = Some(cursor);
164165

165166
// If it's an instantiation of another template,
@@ -538,12 +539,34 @@ fn opaque_ty(ctx: &mut ClangParserCtx, ty: &cx::Type) {
538539
}
539540
}
540541

541-
struct Annotations {
542+
#[derive(Copy, PartialEq, Clone, Debug)]
543+
pub enum Accessor {
544+
None,
545+
Regular,
546+
Unsafe,
547+
Immutable,
548+
}
549+
550+
#[derive(Clone, PartialEq, Debug)]
551+
pub struct Annotations {
542552
opaque: bool,
543553
hide: bool,
544554
use_as: Option<String>,
545555
/// Disable deriving copy/clone on this struct.
546556
no_copy: bool,
557+
// In the None case we fall back to the value specified
558+
// in the enclosing decl
559+
private: Option<bool>,
560+
accessor: Option<Accessor>,
561+
}
562+
563+
fn parse_accessor(s: &str) -> Accessor {
564+
match s {
565+
"false" => Accessor::None,
566+
"unsafe" => Accessor::Unsafe,
567+
"immutable" => Accessor::Immutable,
568+
_ => Accessor::Regular,
569+
}
547570
}
548571

549572
impl Annotations {
@@ -553,6 +576,8 @@ impl Annotations {
553576
hide: false,
554577
use_as: None,
555578
no_copy: false,
579+
private: None,
580+
accessor: None
556581
};
557582

558583
anno.parse(&cursor.comment());
@@ -571,6 +596,10 @@ impl Annotations {
571596
"hide" => self.hide = true,
572597
"replaces" => self.use_as = Some(comment.get_tag_attr_value(i)),
573598
"nocopy" => self.no_copy = true,
599+
"private" => self.private = Some(comment.get_tag_attr_value(i) != "false"),
600+
"accessor" => {
601+
self.accessor = Some(parse_accessor(&comment.get_tag_attr_value(i)))
602+
},
574603
_ => (),
575604
}
576605
}
@@ -792,12 +821,16 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
792821

793822
if should_replace {
794823
*info = FieldInfo::new(name, ty, comment, bitfields, mutable);
824+
info.private = anno.private.unwrap_or(ci.anno.private.unwrap_or(false));
825+
info.accessor = anno.accessor.unwrap_or(ci.anno.accessor.unwrap_or(Accessor::None));
795826
return CXChildVisit_Continue;
796827
}
797828
}
798829
}
799830

800-
let field = FieldInfo::new(name, ty, comment, bitfields, mutable);
831+
let mut field = FieldInfo::new(name, ty, comment, bitfields, mutable);
832+
field.private = anno.private.unwrap_or(ci.anno.private.unwrap_or(false));
833+
field.accessor = anno.accessor.unwrap_or(ci.anno.accessor.unwrap_or(Accessor::None));
801834
ci.members.push(CompMember::Field(field));
802835
}
803836
CXCursor_StructDecl |

src/types.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ pub use self::IKind::*;
1313
pub use self::FKind::*;
1414
use clang::Cursor;
1515

16+
use parser::{Annotations, Accessor};
17+
1618
static NEXT_MODULE_ID: AtomicUsize = ATOMIC_USIZE_INIT;
1719

1820
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
@@ -446,6 +448,9 @@ pub struct CompInfo {
446448
/// Used to detect if we've run in a has_destructor cycle while cycling
447449
/// around the template arguments.
448450
detect_has_destructor_cycle: Cell<bool>,
451+
452+
/// Annotations on the decl
453+
pub anno: Annotations,
449454
}
450455

451456
static mut UNNAMED_COUNTER: u32 = 0;
@@ -466,7 +471,8 @@ impl CompInfo {
466471
comment: String,
467472
kind: CompKind,
468473
members: Vec<CompMember>,
469-
layout: Layout) -> CompInfo {
474+
layout: Layout,
475+
anno: Annotations) -> CompInfo {
470476
let was_unnamed = name.is_empty();
471477
CompInfo {
472478
kind: kind,
@@ -494,6 +500,7 @@ impl CompInfo {
494500
was_unnamed: was_unnamed,
495501
detect_derive_debug_cycle: Cell::new(false),
496502
detect_has_destructor_cycle: Cell::new(false),
503+
anno: anno,
497504
}
498505
}
499506

@@ -640,6 +647,12 @@ pub struct FieldInfo {
640647
pub bitfields: Option<Vec<(String, u32)>>,
641648
/// If the C++ field is marked as `mutable`
642649
pub mutable: bool,
650+
/// True when field or enclosing struct
651+
/// has a `<div rust-bindgen private>` annotation
652+
pub private: bool,
653+
/// Set by the `<div rust-bindgen accessor="..">`
654+
/// annotation on a field or enclosing struct
655+
pub accessor: Accessor,
643656
}
644657

645658
impl FieldInfo {
@@ -654,6 +667,8 @@ impl FieldInfo {
654667
comment: comment,
655668
bitfields: bitfields,
656669
mutable: mutable,
670+
private: false,
671+
accessor: Accessor::None,
657672
}
658673
}
659674
}

0 commit comments

Comments
 (0)