Skip to content

Commit 79a03e4

Browse files
committed
Define a type for communicating that the constraint function hasn't reached a fixed point
`ConstrainResult::Changed` is much more legible than `true`.
1 parent de71f9c commit 79a03e4

File tree

3 files changed

+95
-52
lines changed

3 files changed

+95
-52
lines changed

src/ir/analysis/derive_debug.rs

Lines changed: 66 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Determining which types for which we can emit `#[derive(Debug)]`.
2-
use super::MonotoneFramework;
2+
3+
use super::{ConstrainResult, MonotoneFramework};
34
use ir::context::{BindgenContext, ItemId};
45
use ir::item::ItemSet;
56
use std::collections::HashSet;
@@ -77,15 +78,15 @@ impl<'ctx, 'gen> CannotDeriveDebug<'ctx, 'gen> {
7778
}
7879
}
7980

80-
fn insert(&mut self, id: ItemId) -> bool {
81+
fn insert(&mut self, id: ItemId) -> ConstrainResult {
8182
let was_not_already_in_set = self.cannot_derive_debug.insert(id);
8283
assert!(
8384
was_not_already_in_set,
8485
"We shouldn't try and insert {:?} twice because if it was \
8586
already in the set, `constrain` should have exited early.",
8687
id
8788
);
88-
true
89+
ConstrainResult::Changed
8990
}
9091
}
9192

@@ -137,20 +138,20 @@ impl<'ctx, 'gen> MonotoneFramework for CannotDeriveDebug<'ctx, 'gen> {
137138
self.ctx.whitelisted_items().iter().cloned().collect()
138139
}
139140

140-
fn constrain(&mut self, id: ItemId) -> bool {
141+
fn constrain(&mut self, id: ItemId) -> ConstrainResult {
141142
if self.cannot_derive_debug.contains(&id) {
142-
return false;
143+
return ConstrainResult::Same;
143144
}
144145

145146
let item = self.ctx.resolve_item(id);
146147
let ty = match item.as_type() {
147-
None => return false,
148+
None => return ConstrainResult::Same,
148149
Some(ty) => ty
149150
};
150151

151152
match *ty.kind() {
152153
// Handle the simple cases. These can derive debug without further
153-
// information
154+
// information.
154155
TypeKind::Void |
155156
TypeKind::NullPtr |
156157
TypeKind::Int(..) |
@@ -165,96 +166,112 @@ impl<'ctx, 'gen> MonotoneFramework for CannotDeriveDebug<'ctx, 'gen> {
165166
TypeKind::ObjCInterface(..) |
166167
TypeKind::ObjCId |
167168
TypeKind::ObjCSel => {
168-
return false;
169+
ConstrainResult::Same
169170
},
171+
170172
TypeKind::Opaque => {
171173
if ty.layout(self.ctx)
172174
.map_or(true, |l| l.opaque().can_trivially_derive_debug(self.ctx, ())) {
173-
return false;
175+
ConstrainResult::Same
174176
} else {
175-
return self.insert(id);
177+
self.insert(id)
176178
}
177179
},
180+
178181
TypeKind::Array(t, len) => {
182+
if self.cannot_derive_debug.contains(&t) {
183+
return self.insert(id);
184+
}
185+
179186
if len <= RUST_DERIVE_IN_ARRAY_LIMIT {
180-
if self.cannot_derive_debug.contains(&t) {
181-
return self.insert(id);
182-
}
183-
return false;
187+
ConstrainResult::Same
184188
} else {
185-
return self.insert(id);
189+
self.insert(id)
186190
}
187191
},
192+
188193
TypeKind::ResolvedTypeRef(t) |
189194
TypeKind::TemplateAlias(t, _) |
190195
TypeKind::Alias(t) => {
191196
if self.cannot_derive_debug.contains(&t) {
192-
return self.insert(id);
197+
self.insert(id)
198+
} else {
199+
ConstrainResult::Same
193200
}
194-
return false;
195201
},
202+
196203
TypeKind::Comp(ref info) => {
197204
if info.has_non_type_template_params() {
198-
if ty.layout(self.ctx).map_or(true,
199-
|l| l.opaque().can_trivially_derive_debug(self.ctx, ())) {
200-
return false;
205+
if ty.layout(self.ctx)
206+
.map_or(true,
207+
|l| l.opaque().can_trivially_derive_debug(self.ctx, ())) {
208+
return ConstrainResult::Same;
201209
} else {
202210
return self.insert(id);
203211
}
204212
}
213+
205214
if info.kind() == CompKind::Union {
206215
if self.ctx.options().unstable_rust {
207216
return self.insert(id);
208217
}
209218

210-
if ty.layout(self.ctx).map_or(true,
211-
|l| l.opaque().can_trivially_derive_debug(self.ctx, ())) {
212-
return false;
219+
if ty.layout(self.ctx)
220+
.map_or(true,
221+
|l| l.opaque().can_trivially_derive_debug(self.ctx, ())) {
222+
return ConstrainResult::Same;
213223
} else {
214224
return self.insert(id);
215225
}
216226
}
227+
217228
let bases_cannot_derive = info.base_members()
218229
.iter()
219230
.any(|base| self.cannot_derive_debug.contains(&base.ty));
220231
if bases_cannot_derive {
221232
return self.insert(id);
222233
}
234+
223235
let fields_cannot_derive = info.fields()
224236
.iter()
225237
.any(|f| {
226-
match f {
227-
&Field::DataMember(ref data) => self.cannot_derive_debug.contains(&data.ty()),
228-
&Field::Bitfields(ref bfu) => bfu.bitfields()
229-
.iter().any(|b| {
230-
self.cannot_derive_debug.contains(&b.ty())
231-
})
238+
match *f {
239+
Field::DataMember(ref data) => {
240+
self.cannot_derive_debug.contains(&data.ty())
241+
}
242+
Field::Bitfields(ref bfu) => {
243+
bfu.bitfields()
244+
.iter().any(|b| {
245+
self.cannot_derive_debug.contains(&b.ty())
246+
})
247+
}
232248
}
233249
});
234250
if fields_cannot_derive {
235251
return self.insert(id);
236252
}
237-
false
253+
254+
ConstrainResult::Same
238255
},
256+
239257
TypeKind::Pointer(inner) => {
240-
let inner_type = self.ctx.resolve_type(inner);
241-
if let TypeKind::Function(ref sig) =
242-
*inner_type.canonical_type(self.ctx).kind() {
243-
if sig.can_trivially_derive_debug(&self.ctx, ()) {
244-
return false;
245-
} else {
246-
return self.insert(id);
247-
}
258+
let inner_type = self.ctx.resolve_type(inner).canonical_type(self.ctx);
259+
if let TypeKind::Function(ref sig) = *inner_type.kind() {
260+
if !sig.can_trivially_derive_debug(&self.ctx, ()) {
261+
return self.insert(id);
248262
}
249-
false
263+
}
264+
ConstrainResult::Same
250265
},
266+
251267
TypeKind::TemplateInstantiation(ref template) => {
252268
let args_cannot_derive = template.template_arguments()
253269
.iter()
254270
.any(|arg| self.cannot_derive_debug.contains(&arg));
255271
if args_cannot_derive {
256272
return self.insert(id);
257273
}
274+
258275
let ty_cannot_derive = template.template_definition()
259276
.into_resolver()
260277
.through_type_refs()
@@ -269,19 +286,26 @@ impl<'ctx, 'gen> MonotoneFramework for CannotDeriveDebug<'ctx, 'gen> {
269286
// idea of the layout than the definition does.
270287
if c.has_non_type_template_params() {
271288
let opaque = ty.layout(self.ctx)
272-
.or_else(|| self.ctx.resolve_type(template.template_definition()).layout(self.ctx))
289+
.or_else(|| {
290+
self.ctx
291+
.resolve_type(template.template_definition())
292+
.layout(self.ctx)
293+
})
273294
.unwrap_or(Layout::zero())
274295
.opaque();
275296
Some(!opaque.can_trivially_derive_debug(&self.ctx, ()))
276297
} else {
277298
None
278299
}
279300
})
280-
.unwrap_or_else(|| self.cannot_derive_debug.contains(&template.template_definition()));
301+
.unwrap_or_else(|| {
302+
self.cannot_derive_debug.contains(&template.template_definition())
303+
});
281304
if ty_cannot_derive {
282305
return self.insert(id);
283306
}
284-
false
307+
308+
ConstrainResult::Same
285309
},
286310
}
287311
}

src/ir/analysis/mod.rs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,10 @@ pub trait MonotoneFramework: Sized + fmt::Debug {
8989
///
9090
/// If this results in changing our internal state (ie, we discovered that
9191
/// we have not reached a fix-point and iteration should continue), return
92-
/// `true`. Otherwise, return `false`. When `constrain` returns false for
93-
/// all nodes in the set, we have reached a fix-point and the analysis is
94-
/// complete.
95-
fn constrain(&mut self, node: Self::Node) -> bool;
92+
/// `ConstrainResult::Changed`. Otherwise, return `ConstrainResult::Same`.
93+
/// When `constrain` returns `ConstrainResult::Same` for all nodes in the
94+
/// set, we have reached a fix-point and the analysis is complete.
95+
fn constrain(&mut self, node: Self::Node) -> ConstrainResult;
9696

9797
/// For each node `d` that depends on the given `node`'s current answer when
9898
/// running `constrain(d)`, call `f(d)`. This informs us which new nodes to
@@ -102,6 +102,17 @@ pub trait MonotoneFramework: Sized + fmt::Debug {
102102
where F: FnMut(Self::Node);
103103
}
104104

105+
/// Whether an analysis's `constrain` function modified the incremental results
106+
/// or not.
107+
pub enum ConstrainResult {
108+
/// The incremental results were updated, and the fix-point computation
109+
/// should continue.
110+
Changed,
111+
112+
/// The incremental results were not updated.
113+
Same,
114+
}
115+
105116
/// Run an analysis in the monotone framework.
106117
pub fn analyze<Analysis>(extra: Analysis::Extra) -> Analysis::Output
107118
where Analysis: MonotoneFramework,
@@ -110,7 +121,7 @@ pub fn analyze<Analysis>(extra: Analysis::Extra) -> Analysis::Output
110121
let mut worklist = analysis.initial_worklist();
111122

112123
while let Some(node) = worklist.pop() {
113-
if analysis.constrain(node) {
124+
if let ConstrainResult::Changed = analysis.constrain(node) {
114125
analysis.each_depending_on(node, |needs_work| {
115126
worklist.push(needs_work);
116127
});
@@ -227,7 +238,7 @@ mod tests {
227238
self.graph.0.keys().cloned().collect()
228239
}
229240

230-
fn constrain(&mut self, node: Node) -> bool {
241+
fn constrain(&mut self, node: Node) -> ConstrainResult {
231242
// The set of nodes reachable from a node `x` is
232243
//
233244
// reachable(x) = s_0 U s_1 U ... U reachable(s_0) U reachable(s_1) U ...
@@ -254,7 +265,11 @@ mod tests {
254265
}
255266

256267
let new_size = self.reachable[&node].len();
257-
original_size != new_size
268+
if original_size != new_size {
269+
ConstrainResult::Changed
270+
} else {
271+
ConstrainResult::Same
272+
}
258273
}
259274

260275
fn each_depending_on<F>(&self, node: Node, mut f: F)

src/ir/analysis/template_params.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@
8888
//!
8989
//! See `src/ir/analysis.rs` for more.
9090
91-
use super::MonotoneFramework;
91+
use super::{ConstrainResult, MonotoneFramework};
9292
use ir::context::{BindgenContext, ItemId};
9393
use ir::item::{Item, ItemSet};
9494
use ir::template::{TemplateInstantiation, TemplateParameters};
@@ -468,7 +468,7 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> {
468468
.collect()
469469
}
470470

471-
fn constrain(&mut self, id: ItemId) -> bool {
471+
fn constrain(&mut self, id: ItemId) -> ConstrainResult {
472472
// Invariant: all hash map entries' values are `Some` upon entering and
473473
// exiting this method.
474474
extra_assert!(self.used.values().all(|v| v.is_some()));
@@ -520,7 +520,11 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> {
520520
self.used.insert(id, Some(used_by_this_id));
521521
extra_assert!(self.used.values().all(|v| v.is_some()));
522522

523-
new_len != original_len
523+
if new_len != original_len {
524+
ConstrainResult::Changed
525+
} else {
526+
ConstrainResult::Same
527+
}
524528
}
525529

526530
fn each_depending_on<F>(&self, item: ItemId, mut f: F)

0 commit comments

Comments
 (0)