diff options
author | Nick Fitzgerald <fitzgen@gmail.com> | 2017-07-20 14:28:40 -0700 |
---|---|---|
committer | Nick Fitzgerald <fitzgen@gmail.com> | 2017-07-20 15:36:25 -0700 |
commit | 79a03e4a990e65162e01de488cd67431214403de (patch) | |
tree | 76798985c0d079e472c98f1fb93b3327ce7f7ec1 /src | |
parent | de71f9ce45f45024782a72c1ff55aea5a46a44da (diff) |
Define a type for communicating that the constraint function hasn't reached a fixed point
`ConstrainResult::Changed` is much more legible than `true`.
Diffstat (limited to 'src')
-rw-r--r-- | src/ir/analysis/derive_debug.rs | 108 | ||||
-rw-r--r-- | src/ir/analysis/mod.rs | 29 | ||||
-rw-r--r-- | src/ir/analysis/template_params.rs | 10 |
3 files changed, 95 insertions, 52 deletions
diff --git a/src/ir/analysis/derive_debug.rs b/src/ir/analysis/derive_debug.rs index e5046490..778466f2 100644 --- a/src/ir/analysis/derive_debug.rs +++ b/src/ir/analysis/derive_debug.rs @@ -1,5 +1,6 @@ //! Determining which types for which we can emit `#[derive(Debug)]`. -use super::MonotoneFramework; + +use super::{ConstrainResult, MonotoneFramework}; use ir::context::{BindgenContext, ItemId}; use ir::item::ItemSet; use std::collections::HashSet; @@ -77,7 +78,7 @@ impl<'ctx, 'gen> CannotDeriveDebug<'ctx, 'gen> { } } - fn insert(&mut self, id: ItemId) -> bool { + fn insert(&mut self, id: ItemId) -> ConstrainResult { let was_not_already_in_set = self.cannot_derive_debug.insert(id); assert!( was_not_already_in_set, @@ -85,7 +86,7 @@ impl<'ctx, 'gen> CannotDeriveDebug<'ctx, 'gen> { already in the set, `constrain` should have exited early.", id ); - true + ConstrainResult::Changed } } @@ -137,20 +138,20 @@ impl<'ctx, 'gen> MonotoneFramework for CannotDeriveDebug<'ctx, 'gen> { self.ctx.whitelisted_items().iter().cloned().collect() } - fn constrain(&mut self, id: ItemId) -> bool { + fn constrain(&mut self, id: ItemId) -> ConstrainResult { if self.cannot_derive_debug.contains(&id) { - return false; + return ConstrainResult::Same; } let item = self.ctx.resolve_item(id); let ty = match item.as_type() { - None => return false, + None => return ConstrainResult::Same, Some(ty) => ty }; match *ty.kind() { // Handle the simple cases. These can derive debug without further - // information + // information. TypeKind::Void | TypeKind::NullPtr | TypeKind::Int(..) | @@ -165,89 +166,104 @@ impl<'ctx, 'gen> MonotoneFramework for CannotDeriveDebug<'ctx, 'gen> { TypeKind::ObjCInterface(..) | TypeKind::ObjCId | TypeKind::ObjCSel => { - return false; + ConstrainResult::Same }, + TypeKind::Opaque => { if ty.layout(self.ctx) .map_or(true, |l| l.opaque().can_trivially_derive_debug(self.ctx, ())) { - return false; + ConstrainResult::Same } else { - return self.insert(id); + self.insert(id) } }, + TypeKind::Array(t, len) => { + if self.cannot_derive_debug.contains(&t) { + return self.insert(id); + } + if len <= RUST_DERIVE_IN_ARRAY_LIMIT { - if self.cannot_derive_debug.contains(&t) { - return self.insert(id); - } - return false; + ConstrainResult::Same } else { - return self.insert(id); + self.insert(id) } }, + TypeKind::ResolvedTypeRef(t) | TypeKind::TemplateAlias(t, _) | TypeKind::Alias(t) => { if self.cannot_derive_debug.contains(&t) { - return self.insert(id); + self.insert(id) + } else { + ConstrainResult::Same } - return false; }, + TypeKind::Comp(ref info) => { if info.has_non_type_template_params() { - if ty.layout(self.ctx).map_or(true, - |l| l.opaque().can_trivially_derive_debug(self.ctx, ())) { - return false; + if ty.layout(self.ctx) + .map_or(true, + |l| l.opaque().can_trivially_derive_debug(self.ctx, ())) { + return ConstrainResult::Same; } else { return self.insert(id); } } + if info.kind() == CompKind::Union { if self.ctx.options().unstable_rust { return self.insert(id); } - if ty.layout(self.ctx).map_or(true, - |l| l.opaque().can_trivially_derive_debug(self.ctx, ())) { - return false; + if ty.layout(self.ctx) + .map_or(true, + |l| l.opaque().can_trivially_derive_debug(self.ctx, ())) { + return ConstrainResult::Same; } else { return self.insert(id); } } + let bases_cannot_derive = info.base_members() .iter() .any(|base| self.cannot_derive_debug.contains(&base.ty)); if bases_cannot_derive { return self.insert(id); } + let fields_cannot_derive = info.fields() .iter() .any(|f| { - match f { - &Field::DataMember(ref data) => self.cannot_derive_debug.contains(&data.ty()), - &Field::Bitfields(ref bfu) => bfu.bitfields() - .iter().any(|b| { - self.cannot_derive_debug.contains(&b.ty()) - }) + match *f { + Field::DataMember(ref data) => { + self.cannot_derive_debug.contains(&data.ty()) + } + Field::Bitfields(ref bfu) => { + bfu.bitfields() + .iter().any(|b| { + self.cannot_derive_debug.contains(&b.ty()) + }) + } } }); if fields_cannot_derive { return self.insert(id); } - false + + ConstrainResult::Same }, + TypeKind::Pointer(inner) => { - let inner_type = self.ctx.resolve_type(inner); - if let TypeKind::Function(ref sig) = - *inner_type.canonical_type(self.ctx).kind() { - if sig.can_trivially_derive_debug(&self.ctx, ()) { - return false; - } else { - return self.insert(id); - } + let inner_type = self.ctx.resolve_type(inner).canonical_type(self.ctx); + if let TypeKind::Function(ref sig) = *inner_type.kind() { + if !sig.can_trivially_derive_debug(&self.ctx, ()) { + return self.insert(id); } - false + } + ConstrainResult::Same }, + TypeKind::TemplateInstantiation(ref template) => { let args_cannot_derive = template.template_arguments() .iter() @@ -255,6 +271,7 @@ impl<'ctx, 'gen> MonotoneFramework for CannotDeriveDebug<'ctx, 'gen> { if args_cannot_derive { return self.insert(id); } + let ty_cannot_derive = template.template_definition() .into_resolver() .through_type_refs() @@ -269,7 +286,11 @@ impl<'ctx, 'gen> MonotoneFramework for CannotDeriveDebug<'ctx, 'gen> { // idea of the layout than the definition does. if c.has_non_type_template_params() { let opaque = ty.layout(self.ctx) - .or_else(|| self.ctx.resolve_type(template.template_definition()).layout(self.ctx)) + .or_else(|| { + self.ctx + .resolve_type(template.template_definition()) + .layout(self.ctx) + }) .unwrap_or(Layout::zero()) .opaque(); Some(!opaque.can_trivially_derive_debug(&self.ctx, ())) @@ -277,11 +298,14 @@ impl<'ctx, 'gen> MonotoneFramework for CannotDeriveDebug<'ctx, 'gen> { None } }) - .unwrap_or_else(|| self.cannot_derive_debug.contains(&template.template_definition())); + .unwrap_or_else(|| { + self.cannot_derive_debug.contains(&template.template_definition()) + }); if ty_cannot_derive { return self.insert(id); } - false + + ConstrainResult::Same }, } } diff --git a/src/ir/analysis/mod.rs b/src/ir/analysis/mod.rs index 472b5dd3..5fe6785b 100644 --- a/src/ir/analysis/mod.rs +++ b/src/ir/analysis/mod.rs @@ -89,10 +89,10 @@ pub trait MonotoneFramework: Sized + fmt::Debug { /// /// If this results in changing our internal state (ie, we discovered that /// we have not reached a fix-point and iteration should continue), return - /// `true`. Otherwise, return `false`. When `constrain` returns false for - /// all nodes in the set, we have reached a fix-point and the analysis is - /// complete. - fn constrain(&mut self, node: Self::Node) -> bool; + /// `ConstrainResult::Changed`. Otherwise, return `ConstrainResult::Same`. + /// When `constrain` returns `ConstrainResult::Same` for all nodes in the + /// set, we have reached a fix-point and the analysis is complete. + fn constrain(&mut self, node: Self::Node) -> ConstrainResult; /// For each node `d` that depends on the given `node`'s current answer when /// running `constrain(d)`, call `f(d)`. This informs us which new nodes to @@ -102,6 +102,17 @@ pub trait MonotoneFramework: Sized + fmt::Debug { where F: FnMut(Self::Node); } +/// Whether an analysis's `constrain` function modified the incremental results +/// or not. +pub enum ConstrainResult { + /// The incremental results were updated, and the fix-point computation + /// should continue. + Changed, + + /// The incremental results were not updated. + Same, +} + /// Run an analysis in the monotone framework. pub fn analyze<Analysis>(extra: Analysis::Extra) -> Analysis::Output where Analysis: MonotoneFramework, @@ -110,7 +121,7 @@ pub fn analyze<Analysis>(extra: Analysis::Extra) -> Analysis::Output let mut worklist = analysis.initial_worklist(); while let Some(node) = worklist.pop() { - if analysis.constrain(node) { + if let ConstrainResult::Changed = analysis.constrain(node) { analysis.each_depending_on(node, |needs_work| { worklist.push(needs_work); }); @@ -227,7 +238,7 @@ mod tests { self.graph.0.keys().cloned().collect() } - fn constrain(&mut self, node: Node) -> bool { + fn constrain(&mut self, node: Node) -> ConstrainResult { // The set of nodes reachable from a node `x` is // // reachable(x) = s_0 U s_1 U ... U reachable(s_0) U reachable(s_1) U ... @@ -254,7 +265,11 @@ mod tests { } let new_size = self.reachable[&node].len(); - original_size != new_size + if original_size != new_size { + ConstrainResult::Changed + } else { + ConstrainResult::Same + } } fn each_depending_on<F>(&self, node: Node, mut f: F) diff --git a/src/ir/analysis/template_params.rs b/src/ir/analysis/template_params.rs index df6cab69..44878d9e 100644 --- a/src/ir/analysis/template_params.rs +++ b/src/ir/analysis/template_params.rs @@ -88,7 +88,7 @@ //! //! See `src/ir/analysis.rs` for more. -use super::MonotoneFramework; +use super::{ConstrainResult, MonotoneFramework}; use ir::context::{BindgenContext, ItemId}; use ir::item::{Item, ItemSet}; use ir::template::{TemplateInstantiation, TemplateParameters}; @@ -468,7 +468,7 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { .collect() } - fn constrain(&mut self, id: ItemId) -> bool { + fn constrain(&mut self, id: ItemId) -> ConstrainResult { // Invariant: all hash map entries' values are `Some` upon entering and // exiting this method. extra_assert!(self.used.values().all(|v| v.is_some())); @@ -520,7 +520,11 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> { self.used.insert(id, Some(used_by_this_id)); extra_assert!(self.used.values().all(|v| v.is_some())); - new_len != original_len + if new_len != original_len { + ConstrainResult::Changed + } else { + ConstrainResult::Same + } } fn each_depending_on<F>(&self, item: ItemId, mut f: F) |