Skip to content

Commit 2e14b19

Browse files
committed
Define extra assertion macros
This commit defines a new set of assertion macros that are only checked in testing/CI when the `testing_only_extra_assertions` feature is enabled. This makes it so that *users* of bindgen that happen to be making a debug build don't enable all these extra and expensive assertions. Additionally, this removes the `testing_only_assert_no_dangling_items` feature, and runs the assertions that were previously gated on that feature when the new `testing_only_extra_assertions` feature is enabled.
1 parent 88b7cd6 commit 2e14b19

File tree

12 files changed

+81
-46
lines changed

12 files changed

+81
-46
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,6 @@ static = []
7070

7171
# These features only exist for CI testing -- don't use them if you're not hacking
7272
# on bindgen!
73-
testing_only_assert_no_dangling_items = []
7473
testing_only_docs = []
74+
testing_only_extra_assertions = []
7575
testing_only_llvm_stable = []

ci/test.sh

+5-2
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ cd "$(dirname "$0")/.."
66
# Regenerate the test headers' bindings in debug and release modes, and assert
77
# that we always get the expected generated bindings.
88

9-
cargo test --features "$BINDGEN_FEATURES testing_only_assert_no_dangling_items"
9+
cargo test --features "$BINDGEN_FEATURES"
10+
./ci/assert-no-diff.sh
11+
12+
cargo test --features "$BINDGEN_FEATURES testing_only_extra_assertions"
1013
./ci/assert-no-diff.sh
1114

12-
cargo test --release --features "$BINDGEN_FEATURES testing_only_assert_no_dangling_items"
15+
cargo test --release --features "$BINDGEN_FEATURES testing_only_extra_assertions"
1316
./ci/assert-no-diff.sh
1417

1518
# Now test the expectations' size and alignment tests.

src/clang.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ impl Cursor {
152152
if n >= 0 {
153153
Some(n as u32)
154154
} else {
155-
debug_assert_eq!(n, -1);
155+
extra_assert_eq!(n, -1);
156156
None
157157
}
158158
})
@@ -813,7 +813,7 @@ impl Type {
813813
if n >= 0 {
814814
Some(n as u32)
815815
} else {
816-
debug_assert_eq!(n, -1);
816+
extra_assert_eq!(n, -1);
817817
None
818818
}
819819
}
@@ -842,7 +842,7 @@ impl Type {
842842
let ret = Type {
843843
x: unsafe { clang_getPointeeType(self.x) },
844844
};
845-
debug_assert!(ret.is_valid());
845+
extra_assert!(ret.is_valid());
846846
Some(ret)
847847
}
848848
_ => None,

src/codegen/mod.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -1202,9 +1202,9 @@ impl CodeGenerator for CompInfo {
12021202
let mut methods = vec![];
12031203
let mut anonymous_field_count = 0;
12041204
for field in struct_fields {
1205-
debug_assert_eq!(current_bitfield_width.is_some(),
1205+
extra_assert_eq!(current_bitfield_width.is_some(),
12061206
current_bitfield_layout.is_some());
1207-
debug_assert_eq!(current_bitfield_width.is_some(),
1207+
extra_assert_eq!(current_bitfield_width.is_some(),
12081208
!current_bitfield_fields.is_empty());
12091209

12101210
let field_ty = ctx.resolve_type(field.ty());
@@ -1226,7 +1226,7 @@ impl CodeGenerator for CompInfo {
12261226

12271227
// Flush the current bitfield.
12281228
if current_bitfield_width.is_some() {
1229-
debug_assert!(!current_bitfield_fields.is_empty());
1229+
extra_assert!(!current_bitfield_fields.is_empty());
12301230
let bitfield_fields =
12311231
mem::replace(&mut current_bitfield_fields, vec![]);
12321232
let bitfield_layout = Bitfield::new(&mut bitfield_count,
@@ -1237,7 +1237,7 @@ impl CodeGenerator for CompInfo {
12371237
current_bitfield_width = None;
12381238
current_bitfield_layout = None;
12391239
}
1240-
debug_assert!(current_bitfield_fields.is_empty());
1240+
extra_assert!(current_bitfield_fields.is_empty());
12411241

12421242
if let Some(width) = field.bitfield() {
12431243
let layout = field_ty.layout(ctx)
@@ -1381,15 +1381,15 @@ impl CodeGenerator for CompInfo {
13811381
// FIXME: Reduce duplication with the loop above.
13821382
// FIXME: May need to pass current_bitfield_layout too.
13831383
if current_bitfield_width.is_some() {
1384-
debug_assert!(!current_bitfield_fields.is_empty());
1384+
extra_assert!(!current_bitfield_fields.is_empty());
13851385
let bitfield_fields = mem::replace(&mut current_bitfield_fields,
13861386
vec![]);
13871387
let bitfield_layout = Bitfield::new(&mut bitfield_count,
13881388
bitfield_fields)
13891389
.codegen_fields(ctx, self, &mut fields, &mut methods);
13901390
struct_layout.saw_bitfield_batch(bitfield_layout);
13911391
}
1392-
debug_assert!(current_bitfield_fields.is_empty());
1392+
extra_assert!(current_bitfield_fields.is_empty());
13931393

13941394
if is_union && !ctx.options().unstable_rust {
13951395
let layout = layout.expect("Unable to get layout information?");
@@ -2642,7 +2642,7 @@ impl TryToRustTy for TemplateInstantiation {
26422642
// This can happen if we generated an opaque type for a partial
26432643
// template specialization, and we've hit an instantiation of
26442644
// that partial specialization.
2645-
debug_assert!(ctx.resolve_type_through_type_refs(decl)
2645+
extra_assert!(ctx.resolve_type_through_type_refs(decl)
26462646
.is_opaque());
26472647
return Err(error::Error::InstantiationOfOpaqueType);
26482648
}

src/extra_assertions.rs

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//! Macros for defining extra assertions that should only be checked in testing
2+
//! and/or CI when the `testing_only_extra_assertions` feature is enabled.
3+
4+
#[macro_export]
5+
macro_rules! extra_assert {
6+
( $cond:expr ) => {
7+
if cfg!(feature = "testing_only_extra_assertions") {
8+
assert!($cond);
9+
}
10+
};
11+
( $cond:expr , $( $arg:tt )+ ) => {
12+
if cfg!(feature = "testing_only_extra_assertions") {
13+
assert!($cond, $( $arg )* )
14+
}
15+
};
16+
}
17+
18+
#[macro_export]
19+
macro_rules! extra_assert_eq {
20+
( $lhs:expr , $rhs:expr ) => {
21+
if cfg!(feature = "testing_only_extra_assertions") {
22+
assert_eq!($lhs, $rhs);
23+
}
24+
};
25+
( $lhs:expr , $rhs:expr , $( $arg:tt )+ ) => {
26+
if cfg!(feature = "testing_only_extra_assertions") {
27+
assert!($lhs, $rhs, $( $arg )* );
28+
}
29+
};
30+
}

src/ir/comp.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,7 @@ impl CompInfo {
645645
CXCursor_CXXMethod => {
646646
let is_virtual = cur.method_is_virtual();
647647
let is_static = cur.method_is_static();
648-
debug_assert!(!(is_static && is_virtual), "How?");
648+
extra_assert!(!(is_static && is_virtual), "How?");
649649

650650
ci.has_destructor |= cur.kind() == CXCursor_Destructor;
651651
ci.has_vtable |= is_virtual;

src/ir/context.rs

+15-16
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ impl<'ctx> BindgenContext<'ctx> {
250250
item,
251251
declaration,
252252
location);
253-
debug_assert!(declaration.is_some() || !item.kind().is_type() ||
253+
extra_assert!(declaration.is_some() || !item.kind().is_type() ||
254254
item.kind().expect_type().is_builtin_or_named() ||
255255
item.kind().expect_type().is_opaque(),
256256
"Adding a type without declaration?");
@@ -310,7 +310,7 @@ impl<'ctx> BindgenContext<'ctx> {
310310
};
311311

312312
let old = self.types.insert(key, id);
313-
debug_assert_eq!(old, None);
313+
extra_assert_eq!(old, None);
314314
}
315315
}
316316

@@ -397,7 +397,7 @@ impl<'ctx> BindgenContext<'ctx> {
397397
fn collect_typerefs
398398
(&mut self)
399399
-> Vec<(ItemId, clang::Type, clang::Cursor, Option<ItemId>)> {
400-
debug_assert!(!self.collected_typerefs);
400+
extra_assert!(!self.collected_typerefs);
401401
self.collected_typerefs = true;
402402
let mut typerefs = vec![];
403403
for (id, ref mut item) in &mut self.items {
@@ -439,7 +439,7 @@ impl<'ctx> BindgenContext<'ctx> {
439439
// Something in the STL is trolling me. I don't need this assertion
440440
// right now, but worth investigating properly once this lands.
441441
//
442-
// debug_assert!(self.items.get(&resolved).is_some(), "How?");
442+
// extra_assert!(self.items.get(&resolved).is_some(), "How?");
443443
}
444444
}
445445

@@ -584,12 +584,11 @@ impl<'ctx> BindgenContext<'ctx> {
584584
ret
585585
}
586586

587-
/// When the `testing_only_assert_no_dangling_items` feature is enabled,
588-
/// this function walks the IR graph and asserts that we do not have any
589-
/// edges referencing an ItemId for which we do not have an associated IR
590-
/// item.
587+
/// When the `testing_only_extra_assertions` feature is enabled, this
588+
/// function walks the IR graph and asserts that we do not have any edges
589+
/// referencing an ItemId for which we do not have an associated IR item.
591590
fn assert_no_dangling_references(&self) {
592-
if cfg!(feature = "testing_only_assert_no_dangling_items") {
591+
if cfg!(feature = "testing_only_extra_assertions") {
593592
for _ in self.assert_no_dangling_item_traversal() {
594593
// The iterator's next method does the asserting for us.
595594
}
@@ -657,7 +656,7 @@ impl<'ctx> BindgenContext<'ctx> {
657656
// -> builtin type ItemId would be the best to improve that.
658657
fn add_builtin_item(&mut self, item: Item) {
659658
debug!("add_builtin_item: item = {:?}", item);
660-
debug_assert!(item.kind().is_type());
659+
extra_assert!(item.kind().is_type());
661660
let id = item.id();
662661
let old_item = self.items.insert(id, item);
663662
assert!(old_item.is_none(), "Inserted type twice?");
@@ -919,7 +918,7 @@ impl<'ctx> BindgenContext<'ctx> {
919918
debug!("instantiate_template: inserting nested \
920919
instantiation item: {:?}",
921920
sub_item);
922-
debug_assert!(sub_id == sub_item.id());
921+
extra_assert!(sub_id == sub_item.id());
923922
self.items.insert(sub_id, sub_item);
924923
args.push(sub_id);
925924
}
@@ -964,7 +963,7 @@ impl<'ctx> BindgenContext<'ctx> {
964963

965964
// Bypass all the validations in add_item explicitly.
966965
debug!("instantiate_template: inserting item: {:?}", item);
967-
debug_assert!(with_id == item.id());
966+
extra_assert!(with_id == item.id());
968967
self.items.insert(with_id, item);
969968
Some(with_id)
970969
}
@@ -1152,7 +1151,7 @@ impl<'ctx> BindgenContext<'ctx> {
11521151

11531152
/// Get the currently parsed macros.
11541153
pub fn parsed_macros(&self) -> &HashMap<Vec<u8>, cexpr::expr::EvalResult> {
1155-
debug_assert!(!self.in_codegen_phase());
1154+
extra_assert!(!self.in_codegen_phase());
11561155
&self.parsed_macros
11571156
}
11581157

@@ -1194,7 +1193,7 @@ impl<'ctx> BindgenContext<'ctx> {
11941193
/// Is the item with the given `name` hidden? Or is the item with the given
11951194
/// `name` and `id` replaced by another type, and effectively hidden?
11961195
pub fn hidden_by_name(&self, path: &[String], id: ItemId) -> bool {
1197-
debug_assert!(self.in_codegen_phase(),
1196+
extra_assert!(self.in_codegen_phase(),
11981197
"You're not supposed to call this yet");
11991198
self.options.hidden_types.matches(&path[1..].join("::")) ||
12001199
self.is_replaced_type(path, id)
@@ -1211,7 +1210,7 @@ impl<'ctx> BindgenContext<'ctx> {
12111210

12121211
/// Is the type with the given `name` marked as opaque?
12131212
pub fn opaque_by_name(&self, path: &[String]) -> bool {
1214-
debug_assert!(self.in_codegen_phase(),
1213+
extra_assert!(self.in_codegen_phase(),
12151214
"You're not supposed to call this yet");
12161215
self.options.opaque_types.matches(&path[1..].join("::"))
12171216
}
@@ -1298,7 +1297,7 @@ impl<'ctx> BindgenContext<'ctx> {
12981297
pub fn with_module<F>(&mut self, module_id: ItemId, cb: F)
12991298
where F: FnOnce(&mut Self),
13001299
{
1301-
debug_assert!(self.resolve_item(module_id).kind().is_module(), "Wat");
1300+
extra_assert!(self.resolve_item(module_id).kind().is_module(), "Wat");
13021301

13031302
let previous_id = self.current_module;
13041303
self.current_module = module_id;

src/ir/item.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ pub trait ItemAncestors {
7070
}
7171

7272
cfg_if! {
73-
if #[cfg(debug_assertions)] {
73+
if #[cfg(testing_only_extra_assertions)] {
7474
type DebugOnlyItemSet = ItemSet;
7575
} else {
7676
struct DebugOnlyItemSet;
@@ -123,7 +123,7 @@ impl<'a, 'b> Iterator for ItemAncestorsIter<'a, 'b>
123123
} else {
124124
self.item = item.parent_id();
125125

126-
debug_assert!(!self.seen.contains(&item.id()));
126+
extra_assert!(!self.seen.contains(&item.id()));
127127
self.seen.insert(item.id());
128128

129129
Some(item.id())
@@ -163,7 +163,7 @@ impl AsNamed for ItemKind {
163163
// Pure convenience
164164
impl ItemCanonicalName for ItemId {
165165
fn canonical_name(&self, ctx: &BindgenContext) -> String {
166-
debug_assert!(ctx.in_codegen_phase(),
166+
extra_assert!(ctx.in_codegen_phase(),
167167
"You're not supposed to call this yet");
168168
ctx.resolve_item(*self).canonical_name(ctx)
169169
}
@@ -173,13 +173,13 @@ impl ItemCanonicalPath for ItemId {
173173
fn namespace_aware_canonical_path(&self,
174174
ctx: &BindgenContext)
175175
-> Vec<String> {
176-
debug_assert!(ctx.in_codegen_phase(),
176+
extra_assert!(ctx.in_codegen_phase(),
177177
"You're not supposed to call this yet");
178178
ctx.resolve_item(*self).namespace_aware_canonical_path(ctx)
179179
}
180180

181181
fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String> {
182-
debug_assert!(ctx.in_codegen_phase(),
182+
extra_assert!(ctx.in_codegen_phase(),
183183
"You're not supposed to call this yet");
184184
ctx.resolve_item(*self).canonical_path(ctx)
185185
}
@@ -418,7 +418,7 @@ impl Item {
418418
parent_id: ItemId,
419419
kind: ItemKind)
420420
-> Self {
421-
debug_assert!(id != parent_id || kind.is_module());
421+
extra_assert!(id != parent_id || kind.is_module());
422422
Item {
423423
id: id,
424424
local_id: Cell::new(None),
@@ -573,15 +573,15 @@ impl Item {
573573
///
574574
/// This may be due to either annotations or to other kind of configuration.
575575
pub fn is_hidden(&self, ctx: &BindgenContext) -> bool {
576-
debug_assert!(ctx.in_codegen_phase(),
576+
extra_assert!(ctx.in_codegen_phase(),
577577
"You're not supposed to call this yet");
578578
self.annotations.hide() ||
579579
ctx.hidden_by_name(&self.canonical_path(ctx), self.id)
580580
}
581581

582582
/// Is this item opaque?
583583
pub fn is_opaque(&self, ctx: &BindgenContext) -> bool {
584-
debug_assert!(ctx.in_codegen_phase(),
584+
extra_assert!(ctx.in_codegen_phase(),
585585
"You're not supposed to call this yet");
586586
self.annotations.opaque() ||
587587
self.as_type().map_or(false, |ty| ty.is_opaque()) ||
@@ -614,7 +614,7 @@ impl Item {
614614
let mut item = self;
615615

616616
loop {
617-
debug_assert!(!targets_seen.contains(&item.id()));
617+
extra_assert!(!targets_seen.contains(&item.id()));
618618
targets_seen.insert(item.id());
619619

620620
if self.annotations().use_instead_of().is_some() {
@@ -1402,7 +1402,7 @@ impl ClangItemParser for Item {
14021402

14031403
impl ItemCanonicalName for Item {
14041404
fn canonical_name(&self, ctx: &BindgenContext) -> String {
1405-
debug_assert!(ctx.in_codegen_phase(),
1405+
extra_assert!(ctx.in_codegen_phase(),
14061406
"You're not supposed to call this yet");
14071407
if self.canonical_name_cache.borrow().is_none() {
14081408
let in_namespace = ctx.options().enable_cxx_namespaces ||

src/ir/named.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> {
371371
fn constrain(&mut self, id: ItemId) -> bool {
372372
// Invariant: all hash map entries' values are `Some` upon entering and
373373
// exiting this method.
374-
debug_assert!(self.used.values().all(|v| v.is_some()));
374+
extra_assert!(self.used.values().all(|v| v.is_some()));
375375

376376
// Take the set for this id out of the hash map while we mutate it based
377377
// on other hash map entries. We *must* put it back into the hash map at
@@ -437,7 +437,7 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> {
437437

438438
// Put the set back in the hash map and restore our invariant.
439439
self.used.insert(id, Some(used_by_this_id));
440-
debug_assert!(self.used.values().all(|v| v.is_some()));
440+
extra_assert!(self.used.values().all(|v| v.is_some()));
441441

442442
new_len != original_len
443443
}

src/ir/traversal.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -439,9 +439,9 @@ impl<'ctx, 'gen, Storage, Queue, Predicate> Iterator
439439
};
440440

441441
let newly_discovered = self.seen.add(None, id);
442-
debug_assert!(!newly_discovered,
442+
extra_assert!(!newly_discovered,
443443
"should have already seen anything we get out of our queue");
444-
debug_assert!(self.ctx.resolve_item_fallible(id).is_some(),
444+
extra_assert!(self.ctx.resolve_item_fallible(id).is_some(),
445445
"should only get IDs of actual items in our context during traversal");
446446

447447
self.currently_traversing = Some(id);

src/ir/ty.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -894,7 +894,7 @@ impl Type {
894894
/// to comply to the C and C++ layouts, that specify that every type needs
895895
/// to be addressable.
896896
pub fn is_unsized(&self, ctx: &BindgenContext) -> bool {
897-
debug_assert!(ctx.in_codegen_phase(), "Not yet");
897+
extra_assert!(ctx.in_codegen_phase(), "Not yet");
898898

899899
match self.kind {
900900
TypeKind::Void => true,
@@ -1122,7 +1122,7 @@ impl Type {
11221122
CXCursor_TypeAliasDecl => {
11231123
let current = cur.cur_type();
11241124

1125-
debug_assert!(current.kind() ==
1125+
extra_assert!(current.kind() ==
11261126
CXType_Typedef);
11271127

11281128
name = current.spelling();

0 commit comments

Comments
 (0)