Skip to content

Commit db0f7ad

Browse files
author
Thom Chiovoloni
committed
Separate layout tests (wip)
1 parent f568d09 commit db0f7ad

File tree

3 files changed

+98
-16
lines changed

3 files changed

+98
-16
lines changed

src/codegen/mod.rs

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ mod bitfield_unit_tests;
1313
use self::helpers::attributes;
1414
use self::struct_layout::StructLayoutTracker;
1515

16-
use super::BindgenOptions;
16+
use super::{BindgenOptions, LayoutTests};
1717

1818
use ir::analysis::{HasVtable, Sizedness};
1919
use ir::annotations::FieldAccessorKind;
@@ -98,6 +98,12 @@ fn root_import(
9898
struct CodegenResult<'a> {
9999
items: Vec<proc_macro2::TokenStream>,
100100

101+
/// Just the layout tests.
102+
///
103+
/// Used to implement `LayoutTests::EmitOnly`, and empty if that setting is
104+
/// disabled (note that conversely `items` is always populted).
105+
only_tests: Vec<proc_macro2::TokenStream>,
106+
101107
/// A monotonic counter used to add stable unique id's to stuff that doesn't
102108
/// need to be referenced by anything.
103109
codegen_id: &'a Cell<usize>,
@@ -147,6 +153,7 @@ impl<'a> CodegenResult<'a> {
147153
fn new(codegen_id: &'a Cell<usize>) -> Self {
148154
CodegenResult {
149155
items: vec![],
156+
only_tests: vec![],
150157
saw_bindgen_union: false,
151158
saw_incomplete_array: false,
152159
saw_objc: false,
@@ -214,7 +221,10 @@ impl<'a> CodegenResult<'a> {
214221
self.vars_seen.insert(name.into());
215222
}
216223

217-
fn inner<F>(&mut self, cb: F) -> Vec<proc_macro2::TokenStream>
224+
fn inner<F>(
225+
&mut self,
226+
cb: F,
227+
) -> (Vec<proc_macro2::TokenStream>, Vec<proc_macro2::TokenStream>)
218228
where
219229
F: FnOnce(&mut Self),
220230
{
@@ -228,7 +238,7 @@ impl<'a> CodegenResult<'a> {
228238
self.saw_bitfield_unit |= new.saw_bitfield_unit;
229239
self.saw_bindgen_union |= new.saw_bindgen_union;
230240

231-
new.items
241+
(new.items, new.only_tests)
232242
}
233243
}
234244

@@ -435,7 +445,7 @@ impl CodeGenerator for Module {
435445
}
436446

437447
let mut found_any = false;
438-
let inner_items = result.inner(|result| {
448+
let (inner_items, inner_tests) = result.inner(|result| {
439449
result.push(root_import(ctx, item));
440450

441451
let path = item.namespace_aware_canonical_path(ctx).join("::");
@@ -457,7 +467,7 @@ impl CodeGenerator for Module {
457467
}
458468

459469
let name = item.canonical_name(ctx);
460-
let ident = ctx.rust_ident(name);
470+
let ident = ctx.rust_ident(&name);
461471
result.push(if item.id() == ctx.root_module() {
462472
quote! {
463473
#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
@@ -472,6 +482,19 @@ impl CodeGenerator for Module {
472482
}
473483
}
474484
});
485+
if ctx.options().layout_tests == LayoutTests::EmitOnly &&
486+
!result.only_tests.is_empty()
487+
{
488+
// XXX the following appears to work? Or should this just be unsupported.
489+
let test_mod =
490+
ctx.rust_ident(format!("__bindgen_test_mod_{}", name));
491+
result.only_tests.push(quote! {
492+
mod #test_mod {
493+
use super::#ident::*;
494+
#( #inner_tests )*
495+
}
496+
});
497+
}
475498
}
476499
}
477500

@@ -959,7 +982,7 @@ impl CodeGenerator for TemplateInstantiation {
959982
// instantiation is opaque, then its presumably because we don't
960983
// properly understand it (maybe because of specializations), and so we
961984
// shouldn't emit layout tests either.
962-
if !ctx.options().layout_tests || self.is_opaque(ctx, item) {
985+
if !ctx.options().layout_tests.needed() || self.is_opaque(ctx, item) {
963986
return;
964987
}
965988

@@ -1006,7 +1029,9 @@ impl CodeGenerator for TemplateInstantiation {
10061029
stringify!(#ident)));
10071030
}
10081031
};
1009-
1032+
if ctx.options().layout_tests == LayoutTests::EmitOnly {
1033+
result.only_tests.push(item.clone());
1034+
}
10101035
result.push(item);
10111036
}
10121037
}
@@ -1899,7 +1924,9 @@ impl CodeGenerator for CompInfo {
18991924
}
19001925
}
19011926

1902-
if ctx.options().layout_tests && !self.is_forward_declaration() {
1927+
if ctx.options().layout_tests.needed() &&
1928+
!self.is_forward_declaration()
1929+
{
19031930
if let Some(layout) = layout {
19041931
let fn_name =
19051932
format!("bindgen_test_layout_{}", canonical_ident);
@@ -1982,6 +2009,9 @@ impl CodeGenerator for CompInfo {
19822009
#( #check_field_offset )*
19832010
}
19842011
};
2012+
if ctx.options().layout_tests == LayoutTests::EmitOnly {
2013+
result.only_tests.push(item.clone());
2014+
}
19852015
result.push(item);
19862016
}
19872017
}
@@ -3848,8 +3878,11 @@ pub(crate) fn codegen(
38483878
&mut result,
38493879
&(),
38503880
);
3851-
3852-
result.items
3881+
if LayoutTests::EmitOnly == context.options().layout_tests {
3882+
result.only_tests
3883+
} else {
3884+
result.items
3885+
}
38533886
})
38543887
}
38553888

src/lib.rs

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -374,8 +374,14 @@ impl Builder {
374374
})
375375
.count();
376376

377-
if !self.options.layout_tests {
378-
output_vector.push("--no-layout-tests".into());
377+
match self.options.layout_tests {
378+
LayoutTests::Emit => {}
379+
LayoutTests::EmitNone => {
380+
output_vector.push("--no-layout-tests".into())
381+
}
382+
LayoutTests::EmitOnly => {
383+
output_vector.push("--only-layout-tests".into())
384+
}
379385
}
380386

381387
if self.options.impl_debug {
@@ -1088,8 +1094,8 @@ impl Builder {
10881094
}
10891095

10901096
/// Set whether layout tests should be generated.
1091-
pub fn layout_tests(mut self, doit: bool) -> Self {
1092-
self.options.layout_tests = doit;
1097+
pub fn layout_tests(mut self, doit: impl Into<LayoutTests>) -> Self {
1098+
self.options.layout_tests = doit.into();
10931099
self
10941100
}
10951101

@@ -1551,6 +1557,44 @@ impl Builder {
15511557
}
15521558
}
15531559

1560+
/// Setting for layout test generation.
1561+
#[derive(Debug, Clone, PartialEq)]
1562+
pub enum LayoutTests {
1563+
/// Include layout tests in the generated bindings. The default.
1564+
Emit,
1565+
/// Don't include any layout tests.
1566+
EmitNone,
1567+
/// Only emit the layout tests.
1568+
///
1569+
/// The intended use case for this is for separating tests from the
1570+
/// generated bindings (as the tests are by nature non-portable, even if the
1571+
/// bindings otherwise would be).
1572+
///
1573+
/// When used in this manner, you're encouraged to provide an an otherwise
1574+
/// identical set of options (even though many of them are effectively
1575+
/// ignored when this is set).
1576+
EmitOnly,
1577+
}
1578+
1579+
impl LayoutTests {
1580+
pub(crate) fn needed(&self) -> bool {
1581+
match self {
1582+
LayoutTests::Emit | LayoutTests::EmitOnly => true,
1583+
LayoutTests::EmitNone => false,
1584+
}
1585+
}
1586+
}
1587+
1588+
impl From<bool> for LayoutTests {
1589+
fn from(value: bool) -> Self {
1590+
if value {
1591+
LayoutTests::Emit
1592+
} else {
1593+
LayoutTests::EmitNone
1594+
}
1595+
}
1596+
}
1597+
15541598
/// Configuration options for generated bindings.
15551599
#[derive(Debug)]
15561600
struct BindgenOptions {
@@ -1649,7 +1693,7 @@ struct BindgenOptions {
16491693
disable_nested_struct_naming: bool,
16501694

16511695
/// True if we should generate layout tests for generated structures.
1652-
layout_tests: bool,
1696+
layout_tests: LayoutTests,
16531697

16541698
/// True if we should implement the Debug trait for C/C++ structures and types
16551699
/// that do not support automatically deriving Debug.
@@ -1894,7 +1938,7 @@ impl Default for BindgenOptions {
18941938
emit_ast: false,
18951939
emit_ir: false,
18961940
emit_ir_graphviz: None,
1897-
layout_tests: true,
1941+
layout_tests: LayoutTests::Emit,
18981942
impl_debug: false,
18991943
impl_partialeq: false,
19001944
derive_copy: true,

src/options.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,11 @@ where
149149
.takes_value(true)
150150
.multiple(true)
151151
.number_of_values(1),
152+
Arg::with_name("only-layout-tests")
153+
.long("only-layout-tests")
154+
.help(
155+
"Only emit layout tests. Allows separating the tests from the bindings."
156+
),
152157
Arg::with_name("no-layout-tests")
153158
.long("no-layout-tests")
154159
.help("Avoid generating layout tests for any type."),

0 commit comments

Comments
 (0)