From db88e5a498ff8a4c7aa6951095e2d217822b11bf Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 28 Apr 2015 10:06:23 +0200 Subject: [PATCH] dropck: Rejectways trait bounds can indirectly access borrowed data. Namely, we need to catch cases like `trait Child : Parent { }` where `Parent` itself defines methods. --- src/librustc_typeck/check/dropck.rs | 78 +++++++++++++++++------------ 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 5391060cb01..8545e73c4f9 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -450,41 +450,57 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( let dtor_typescheme = ty::lookup_item_type(rcx.tcx(), impl_did); let dtor_generics = dtor_typescheme.generics; - let dtor_predicates = ty::lookup_predicates(rcx.tcx(), impl_did); - let has_pred_of_interest = dtor_predicates.predicates.iter().any(|pred| { - // In `impl Drop where ...`, assume most predicates - // represent capability on `T` via which a destructor - // could access borrowed data. But some bounds (Sized, - // Copy, etc), have no items, i.e. no added capabilty - // for such type-specific access. + let mut has_pred_of_interest = false; - let result = match *pred { - ty::Predicate::Trait(ty::Binder(ref t_pred)) => { - let def_id = t_pred.trait_ref.def_id; - // A OIBIT (or even a normal builtin) trait - // defines no associated items, and is - // uninteresting from point of view of dropck. - ty::trait_items(rcx.tcx(), def_id).len() != 0 - } - ty::Predicate::Equate(..) | - ty::Predicate::RegionOutlives(..) | - ty::Predicate::TypeOutlives(..) | - ty::Predicate::Projection(..) => { - // for now, assume all other where-clauses may - // give the drop implementation the capabilty - // to access borrowed data. - true - } - }; - - if result { - debug!("typ: {} has interesting dtor due to generic preds, e.g. {}", - typ.repr(rcx.tcx()), pred.repr(rcx.tcx())); + let mut seen_items = Vec::new(); + let mut items_to_inspect = vec![impl_did]; + 'items: while let Some(item_def_id) = items_to_inspect.pop() { + if seen_items.contains(&item_def_id) { + continue; } - result - }); + for pred in ty::lookup_predicates(rcx.tcx(), item_def_id).predicates { + let result = match pred { + ty::Predicate::Equate(..) | + ty::Predicate::RegionOutlives(..) | + ty::Predicate::TypeOutlives(..) | + ty::Predicate::Projection(..) => { + // For now, assume all these where-clauses + // may give drop implementation capabilty + // to access borrowed data. + true + } + + ty::Predicate::Trait(ty::Binder(ref t_pred)) => { + let def_id = t_pred.trait_ref.def_id; + if ty::trait_items(rcx.tcx(), def_id).len() != 0 { + // If trait has items, assume it adds + // capability to access borrowed data. + true + } else { + // Trait without items is itself + // uninteresting from POV of dropck. + // + // However, may have parent w/ items; + // so schedule checking of predicates, + items_to_inspect.push(def_id); + // and say "no capability found" for now. + false + } + } + }; + + if result { + has_pred_of_interest = true; + debug!("typ: {} has interesting dtor due to generic preds, e.g. {}", + typ.repr(rcx.tcx()), pred.repr(rcx.tcx())); + break 'items; + } + } + + seen_items.push(item_def_id); + } // In `impl<'a> Drop ...`, we automatically assume // `'a` is meaningful and thus represents a bound