1 // Copyright 2017 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.
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.
11 use borrow_check
::borrow_set
::BorrowSet
;
12 use borrow_check
::location
::{LocationIndex, LocationTable}
;
13 use borrow_check
::nll
::facts
::AllFactsExt
;
14 use borrow_check
::nll
::type_check
::{MirTypeckResults, MirTypeckRegionConstraints}
;
15 use borrow_check
::nll
::type_check
::liveness
::liveness_map
::NllLivenessMap
;
16 use borrow_check
::nll
::region_infer
::values
::RegionValueElements
;
17 use dataflow
::indexes
::BorrowIndex
;
18 use dataflow
::move_paths
::MoveData
;
19 use dataflow
::FlowAtLocation
;
20 use dataflow
::MaybeInitializedPlaces
;
21 use rustc
::hir
::def_id
::DefId
;
22 use rustc
::infer
::InferCtxt
;
23 use rustc
::mir
::{ClosureOutlivesSubject, ClosureRegionRequirements, Mir}
;
24 use rustc
::ty
::{self, RegionKind, RegionVid}
;
25 use rustc_errors
::Diagnostic
;
29 use std
::path
::PathBuf
;
31 use std
::str::FromStr
;
32 use transform
::MirSource
;
34 use self::mir_util
::PassWhere
;
35 use polonius_engine
::{Algorithm, Output}
;
39 mod constraint_generation
;
40 pub mod explain_borrow
;
43 crate mod region_infer
;
46 mod universal_regions
;
50 use self::facts
::AllFacts
;
51 use self::region_infer
::RegionInferenceContext
;
52 use self::universal_regions
::UniversalRegions
;
54 /// Rewrites the regions in the MIR to use NLL variables, also
55 /// scraping out the set of universal regions (e.g., region parameters)
56 /// declared on the function. That set will need to be given to
57 /// `compute_regions`.
58 pub(in borrow_check
) fn replace_regions_in_mir
<'cx
, 'gcx
, 'tcx
>(
59 infcx
: &InferCtxt
<'cx
, 'gcx
, 'tcx
>,
61 param_env
: ty
::ParamEnv
<'tcx
>,
63 ) -> UniversalRegions
<'tcx
> {
64 debug
!("replace_regions_in_mir(def_id={:?})", def_id
);
66 // Compute named region information. This also renumbers the inputs/outputs.
67 let universal_regions
= UniversalRegions
::new(infcx
, def_id
, param_env
);
69 // Replace all remaining regions with fresh inference variables.
70 renumber
::renumber_mir(infcx
, mir
);
72 let source
= MirSource
::item(def_id
);
73 mir_util
::dump_mir(infcx
.tcx
, None
, "renumber", &0, source
, mir
, |_
, _
| Ok(()));
78 /// Computes the (non-lexical) regions from the input MIR.
80 /// This may result in errors being reported.
81 pub(in borrow_check
) fn compute_regions
<'cx
, 'gcx
, 'tcx
>(
82 infcx
: &InferCtxt
<'cx
, 'gcx
, 'tcx
>,
84 universal_regions
: UniversalRegions
<'tcx
>,
86 location_table
: &LocationTable
,
87 param_env
: ty
::ParamEnv
<'gcx
>,
88 flow_inits
: &mut FlowAtLocation
<MaybeInitializedPlaces
<'cx
, 'gcx
, 'tcx
>>,
89 move_data
: &MoveData
<'tcx
>,
90 borrow_set
: &BorrowSet
<'tcx
>,
91 errors_buffer
: &mut Vec
<Diagnostic
>,
93 RegionInferenceContext
<'tcx
>,
94 Option
<Rc
<Output
<RegionVid
, BorrowIndex
, LocationIndex
>>>,
95 Option
<ClosureRegionRequirements
<'gcx
>>,
97 let mut all_facts
= if AllFacts
::enabled(infcx
.tcx
) {
98 Some(AllFacts
::default())
103 let universal_regions
= Rc
::new(universal_regions
);
105 let elements
= &Rc
::new(RegionValueElements
::new(mir
));
107 // Run the MIR type-checker.
108 let MirTypeckResults
{
111 universal_region_relations
,
112 } = type_check
::type_check(
126 let placeholder_indices
= Rc
::new(placeholder_indices
);
128 if let Some(all_facts
) = &mut all_facts
{
131 .extend(universal_regions
.universal_regions());
134 // Create the region inference context, taking ownership of the
135 // region inference data that was contained in `infcx`, and the
136 // base constraints generated by the type-check.
137 let var_origins
= infcx
.take_region_var_origins();
138 let MirTypeckRegionConstraints
{
139 mut liveness_constraints
,
140 outlives_constraints
,
141 closure_bounds_mapping
,
145 constraint_generation
::generate_constraints(
147 &mut liveness_constraints
,
154 let mut regioncx
= RegionInferenceContext
::new(
158 universal_region_relations
,
160 outlives_constraints
,
161 closure_bounds_mapping
,
163 liveness_constraints
,
167 // Generate various additional constraints.
168 invalidation
::generate_invalidates(
176 // Dump facts if requested.
177 let polonius_output
= all_facts
.and_then(|all_facts
| {
178 if infcx
.tcx
.sess
.opts
.debugging_opts
.nll_facts
{
179 let def_path
= infcx
.tcx
.hir
.def_path(def_id
);
181 PathBuf
::from("nll-facts").join(def_path
.to_filename_friendly_no_crate());
182 all_facts
.write_to_dir(dir_path
, location_table
).unwrap();
185 if infcx
.tcx
.sess
.opts
.debugging_opts
.polonius
{
186 let algorithm
= env
::var("POLONIUS_ALGORITHM")
187 .unwrap_or_else(|_
| String
::from("DatafrogOpt"));
188 let algorithm
= Algorithm
::from_str(&algorithm
).unwrap();
189 debug
!("compute_regions: using polonius algorithm {:?}", algorithm
);
190 Some(Rc
::new(Output
::compute(
200 // Solve the region constraints.
201 let closure_region_requirements
= regioncx
.solve(infcx
, &mir
, def_id
, errors_buffer
);
203 // Dump MIR results into a file, if that is enabled. This let us
204 // write unit-tests, as well as helping with debugging.
207 MirSource
::item(def_id
),
210 &closure_region_requirements
,
213 // We also have a `#[rustc_nll]` annotation that causes us to dump
215 dump_annotation(infcx
, &mir
, def_id
, ®ioncx
, &closure_region_requirements
, errors_buffer
);
217 (regioncx
, polonius_output
, closure_region_requirements
)
220 fn dump_mir_results
<'a
, 'gcx
, 'tcx
>(
221 infcx
: &InferCtxt
<'a
, 'gcx
, 'tcx
>,
224 regioncx
: &RegionInferenceContext
,
225 closure_region_requirements
: &Option
<ClosureRegionRequirements
>,
227 if !mir_util
::dump_enabled(infcx
.tcx
, "nll", source
) {
240 // Before the CFG, dump out the values for each region variable.
241 PassWhere
::BeforeCFG
=> {
242 regioncx
.dump_mir(out
)?
;
244 if let Some(closure_region_requirements
) = closure_region_requirements
{
246 writeln
!(out
, "| Free Region Constraints")?
;
247 for_each_region_constraint(closure_region_requirements
, &mut |msg
| {
248 writeln
!(out
, "| {}", msg
)
253 PassWhere
::BeforeLocation(_
) => {
256 PassWhere
::AfterTerminator(_
) => {
259 PassWhere
::BeforeBlock(_
) | PassWhere
::AfterLocation(_
) | PassWhere
::AfterCFG
=> {}
265 // Also dump the inference graph constraints as a graphviz file.
266 let _
: io
::Result
<()> = try_block
! {
268 pretty
::create_dump_file(infcx
.tcx
, "regioncx.all.dot", None
, "nll", &0, source
)?
;
269 regioncx
.dump_graphviz_raw_constraints(&mut file
)?
;
272 // Also dump the inference graph constraints as a graphviz file.
273 let _
: io
::Result
<()> = try_block
! {
275 pretty
::create_dump_file(infcx
.tcx
, "regioncx.scc.dot", None
, "nll", &0, source
)?
;
276 regioncx
.dump_graphviz_scc_constraints(&mut file
)?
;
280 fn dump_annotation
<'a
, 'gcx
, 'tcx
>(
281 infcx
: &InferCtxt
<'a
, 'gcx
, 'tcx
>,
284 regioncx
: &RegionInferenceContext
<'tcx
>,
285 closure_region_requirements
: &Option
<ClosureRegionRequirements
>,
286 errors_buffer
: &mut Vec
<Diagnostic
>,
289 let base_def_id
= tcx
.closure_base_def_id(mir_def_id
);
290 if !tcx
.has_attr(base_def_id
, "rustc_regions") {
294 // When the enclosing function is tagged with `#[rustc_regions]`,
295 // we dump out various bits of state as warnings. This is useful
296 // for verifying that the compiler is behaving as expected. These
297 // warnings focus on the closure region requirements -- for
298 // viewing the intraprocedural state, the -Zdump-mir output is
301 if let Some(closure_region_requirements
) = closure_region_requirements
{
305 .span_note_diag(mir
.span
, "External requirements");
307 regioncx
.annotate(tcx
, &mut err
);
310 "number of external vids: {}",
311 closure_region_requirements
.num_external_vids
314 // Dump the region constraints we are imposing *between* those
315 // newly created variables.
316 for_each_region_constraint(closure_region_requirements
, &mut |msg
| {
321 err
.buffer(errors_buffer
);
326 .span_note_diag(mir
.span
, "No external requirements");
327 regioncx
.annotate(tcx
, &mut err
);
329 err
.buffer(errors_buffer
);
333 fn for_each_region_constraint(
334 closure_region_requirements
: &ClosureRegionRequirements
,
335 with_msg
: &mut dyn FnMut(&str) -> io
::Result
<()>,
336 ) -> io
::Result
<()> {
337 for req
in &closure_region_requirements
.outlives_requirements
{
338 let subject
: &dyn Debug
= match &req
.subject
{
339 ClosureOutlivesSubject
::Region(subject
) => subject
,
340 ClosureOutlivesSubject
::Ty(ty
) => ty
,
344 subject
, req
.outlived_free_region
,
350 /// Right now, we piggy back on the `ReVar` to store our NLL inference
351 /// regions. These are indexed with `RegionVid`. This method will
352 /// assert that the region is a `ReVar` and extract its internal index.
353 /// This is reasonable because in our MIR we replace all universal regions
354 /// with inference variables.
355 pub trait ToRegionVid
{
356 fn to_region_vid(self) -> RegionVid
;
359 impl<'tcx
> ToRegionVid
for &'tcx RegionKind
{
360 fn to_region_vid(self) -> RegionVid
{
361 if let ty
::ReVar(vid
) = self {
364 bug
!("region is not an ReVar: {:?}", self)
369 impl ToRegionVid
for RegionVid
{
370 fn to_region_vid(self) -> RegionVid
{
375 crate trait ConstraintDescription
{
376 fn description(&self) -> &'
static str;