Skip to content

Commit af09f72

Browse files
committed
preliminary support for may-dangle attribute and drop constraints
1 parent e029378 commit af09f72

File tree

3 files changed

+163
-13
lines changed

3 files changed

+163
-13
lines changed

src/librustc_mir/transform/nll/constraint_generation.rs

Lines changed: 112 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,15 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use rustc::mir::Mir;
11+
use rustc::mir::{Location, Mir};
12+
use rustc::mir::transform::MirSource;
1213
use rustc::infer::InferCtxt;
14+
use rustc::traits::{self, ObligationCause};
15+
use rustc::ty::{self, Ty};
16+
use rustc::ty::fold::TypeFoldable;
17+
use rustc::util::common::ErrorReported;
18+
use rustc_data_structures::fx::FxHashSet;
19+
use syntax::codemap::DUMMY_SP;
1320

1421
use super::LivenessResults;
1522
use super::ToRegionIndex;
@@ -19,13 +26,15 @@ pub(super) fn generate_constraints<'a, 'gcx, 'tcx>(
1926
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
2027
regioncx: &mut RegionInferenceContext,
2128
mir: &Mir<'tcx>,
29+
mir_source: MirSource,
2230
liveness: &LivenessResults,
2331
) {
2432
ConstraintGeneration {
2533
infcx,
2634
regioncx,
2735
mir,
2836
liveness,
37+
mir_source,
2938
}.add_constraints();
3039
}
3140

@@ -34,6 +43,7 @@ struct ConstraintGeneration<'constrain, 'gcx: 'tcx, 'tcx: 'constrain> {
3443
regioncx: &'constrain mut RegionInferenceContext,
3544
mir: &'constrain Mir<'tcx>,
3645
liveness: &'constrain LivenessResults,
46+
mir_source: MirSource,
3747
}
3848

3949
impl<'constrain, 'gcx, 'tcx> ConstraintGeneration<'constrain, 'gcx, 'tcx> {
@@ -47,29 +57,119 @@ impl<'constrain, 'gcx, 'tcx> ConstraintGeneration<'constrain, 'gcx, 'tcx> {
4757
/// > If a variable V is live at point P, then all regions R in the type of V
4858
/// > must include the point P.
4959
fn add_liveness_constraints(&mut self) {
50-
let tcx = self.infcx.tcx;
51-
5260
debug!("add_liveness_constraints()");
5361
for bb in self.mir.basic_blocks().indices() {
5462
debug!("add_liveness_constraints: bb={:?}", bb);
5563

5664
self.liveness
5765
.regular
5866
.simulate_block(self.mir, bb, |location, live_locals| {
59-
debug!(
60-
"add_liveness_constraints: location={:?} live_locals={:?}",
61-
location,
62-
live_locals
63-
);
67+
for live_local in live_locals.iter() {
68+
let live_local_ty = self.mir.local_decls[live_local].ty;
69+
self.add_regular_live_constraint(live_local_ty, location);
70+
}
71+
});
6472

73+
self.liveness
74+
.drop
75+
.simulate_block(self.mir, bb, |location, live_locals| {
6576
for live_local in live_locals.iter() {
6677
let live_local_ty = self.mir.local_decls[live_local].ty;
67-
tcx.for_each_free_region(&live_local_ty, |live_region| {
68-
let vid = live_region.to_region_index();
69-
self.regioncx.add_live_point(vid, location);
70-
})
78+
self.add_drop_live_constraint(live_local_ty, location);
7179
}
7280
});
7381
}
7482
}
83+
84+
/// Some variable with type `live_ty` is "regular live" at
85+
/// `location` -- i.e., it may be used later. This means that all
86+
/// regions appearing in the type `live_ty` must be live at
87+
/// `location`.
88+
fn add_regular_live_constraint<T>(&mut self, live_ty: T, location: Location)
89+
where
90+
T: TypeFoldable<'tcx>,
91+
{
92+
debug!(
93+
"add_regular_live_constraint(live_ty={:?}, location={:?})",
94+
live_ty,
95+
location
96+
);
97+
98+
self.infcx
99+
.tcx
100+
.for_each_free_region(&live_ty, |live_region| {
101+
let vid = live_region.to_region_index();
102+
self.regioncx.add_live_point(vid, location);
103+
});
104+
}
105+
106+
/// Some variable with type `live_ty` is "drop live" at `location`
107+
/// -- i.e., it may be dropped later. This means that *some* of
108+
/// the regions in its type must be live at `location`. The
109+
/// precise set will depend on the dropck constraints, and in
110+
/// particular this takes `#[may_dangle]` into account.
111+
fn add_drop_live_constraint(&mut self, dropped_ty: Ty<'tcx>, location: Location) {
112+
debug!(
113+
"add_drop_live_constraint(dropped_ty={:?}, location={:?})",
114+
dropped_ty,
115+
location
116+
);
117+
118+
let tcx = self.infcx.tcx;
119+
let mut types = vec![(dropped_ty, 0)];
120+
let mut known = FxHashSet();
121+
while let Some((ty, depth)) = types.pop() {
122+
let span = DUMMY_SP; // FIXME
123+
let result = match tcx.dtorck_constraint_for_ty(span, dropped_ty, depth, ty) {
124+
Ok(result) => result,
125+
Err(ErrorReported) => {
126+
continue;
127+
}
128+
};
129+
130+
let ty::DtorckConstraint {
131+
outlives,
132+
dtorck_types,
133+
} = result;
134+
135+
// All things in the `outlives` array may be touched by
136+
// the destructor and must be live at this point.
137+
for outlive in outlives {
138+
if let Some(ty) = outlive.as_type() {
139+
self.add_regular_live_constraint(ty, location);
140+
} else if let Some(r) = outlive.as_region() {
141+
self.add_regular_live_constraint(r, location);
142+
} else {
143+
bug!()
144+
}
145+
}
146+
147+
// However, there may also be some types that
148+
// `dtorck_constraint_for_ty` could not resolve (e.g.,
149+
// associated types and parameters). We need to normalize
150+
// associated types here and possibly recursively process.
151+
let def_id = tcx.hir.local_def_id(self.mir_source.item_id());
152+
let param_env = self.infcx.tcx.param_env(def_id);
153+
for ty in dtorck_types {
154+
// FIXME -- I think that this may disregard some region obligations
155+
// or something. Do we care? -nmatsakis
156+
let cause = ObligationCause::dummy();
157+
match traits::fully_normalize(self.infcx, cause, param_env, &ty) {
158+
Ok(ty) => match ty.sty {
159+
ty::TyParam(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
160+
self.add_regular_live_constraint(ty, location);
161+
}
162+
163+
_ => if known.insert(ty) {
164+
types.push((ty, depth + 1));
165+
},
166+
},
167+
168+
Err(errors) => {
169+
self.infcx.report_fulfillment_errors(&errors, None);
170+
}
171+
}
172+
}
173+
}
174+
}
75175
}

src/librustc_mir/transform/nll/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ impl MirPass for NLL {
6565
// Create the region inference context, generate the constraints,
6666
// and then solve them.
6767
let regioncx = &mut RegionInferenceContext::new(num_region_variables);
68-
constraint_generation::generate_constraints(infcx, regioncx, mir, liveness);
68+
constraint_generation::generate_constraints(infcx, regioncx, mir, source, liveness);
6969
regioncx.solve(infcx, mir);
7070

7171
// Dump MIR results into a file, if that is enabled.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Basic test for liveness constraints: the region (`R1`) that appears
12+
// in the type of `p` includes the points after `&v[0]` up to (but not
13+
// including) the call to `use_x`. The `else` branch is not included.
14+
15+
// ignore-tidy-linelength
16+
// compile-flags:-Znll -Zverbose
17+
// ^^^^^^^^^ force compiler to dump more region information
18+
19+
#![allow(warnings)]
20+
21+
fn use_x(_: usize) -> bool { true }
22+
23+
fn main() {
24+
let mut v = [1, 2, 3];
25+
let p: Wrap<& /* R1 */ usize> = Wrap { value: &v[0] };
26+
if true {
27+
use_x(*p.value);
28+
} else {
29+
use_x(22);
30+
}
31+
32+
// `p` will get dropped here. Because the `#[may_dangle]`
33+
// attribute is not present on `Wrap`, we must conservatively
34+
// assume that the dtor may access the `value` field, and hence we
35+
// must consider R1 to be live.
36+
}
37+
38+
struct Wrap<T> {
39+
value: T
40+
}
41+
42+
// Look ma, no `#[may_dangle]` attribute here.
43+
impl<T> Drop for Wrap<T> {
44+
fn drop(&mut self) { }
45+
}
46+
47+
// END RUST SOURCE
48+
// START rustc.node12.nll.0.mir
49+
// | R4: {bb1[3], bb1[4], bb1[5], bb2[0], bb2[1], bb2[2], bb3[0], bb4[0], bb4[1], bb4[2], bb6[0], bb7[0], bb7[1], bb8[0]}
50+
// END rustc.node12.nll.0.mir

0 commit comments

Comments
 (0)