Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 5 pull requests #71703

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 15 additions & 11 deletions src/bootstrap/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import argparse
import contextlib
import datetime
import distutils.version
import hashlib
import os
import re
Expand Down Expand Up @@ -331,6 +332,7 @@ def __init__(self):
self.use_locked_deps = ''
self.use_vendored_sources = ''
self.verbose = False
self.git_version = None

def download_stage0(self):
"""Fetch the build system for Rust, written in Rust
Expand Down Expand Up @@ -743,15 +745,13 @@ def update_submodule(self, module, checked_out, recorded_submodules):

run(["git", "submodule", "-q", "sync", module],
cwd=self.rust_root, verbose=self.verbose)
try:
run(["git", "submodule", "update",
"--init", "--recursive", "--progress", module],
cwd=self.rust_root, verbose=self.verbose, exception=True)
except RuntimeError:
# Some versions of git don't support --progress.
run(["git", "submodule", "update",
"--init", "--recursive", module],
cwd=self.rust_root, verbose=self.verbose)

update_args = ["git", "submodule", "update", "--init", "--recursive"]
if self.git_version >= distutils.version.LooseVersion("2.11.0"):
update_args.append("--progress")
update_args.append(module)
run(update_args, cwd=self.rust_root, verbose=self.verbose, exception=True)

run(["git", "reset", "-q", "--hard"],
cwd=module_path, verbose=self.verbose)
run(["git", "clean", "-qdfx"],
Expand All @@ -763,9 +763,13 @@ def update_submodules(self):
self.get_toml('submodules') == "false":
return

# check the existence of 'git' command
default_encoding = sys.getdefaultencoding()

# check the existence and version of 'git' command
try:
subprocess.check_output(['git', '--version'])
git_version_output = subprocess.check_output(['git', '--version'])
git_version_str = git_version_output.strip().split()[2].decode(default_encoding)
self.git_version = distutils.version.LooseVersion(git_version_str)
except (subprocess.CalledProcessError, OSError):
print("error: `git` is not found, please make sure it's installed and in the path.")
sys.exit(1)
Expand Down
3 changes: 3 additions & 0 deletions src/bootstrap/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1012,4 +1012,7 @@ pub enum CargoMessage<'a> {
BuildScriptExecuted {
package_id: Cow<'a, str>,
},
BuildFinished {
success: bool,
},
}
5 changes: 5 additions & 0 deletions src/librustc_data_structures/graph/scc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ impl<N: Idx, S: Idx> Sccs<N, S> {
}

/// Returns an iterator over the SCCs in the graph.
///
/// The SCCs will be iterated in **dependency order** (or **post order**),
/// meaning that if `S1 -> S2`, we will visit `S2` first and `S1` after.
/// This is convenient when the edges represent dependencies: when you visit
/// `S1`, the value for `S2` will already have been computed.
pub fn all_sccs(&self) -> impl Iterator<Item = S> {
(0..self.scc_data.len()).map(S::new)
}
Expand Down
4 changes: 4 additions & 0 deletions src/librustc_infer/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,9 @@ pub enum NLLRegionVariableOrigin {
/// from a `for<'a> T` binder). Meant to represent "any region".
Placeholder(ty::PlaceholderRegion),

/// The variable we create to represent `'empty(U0)`.
RootEmptyRegion,

Existential {
/// If this is true, then this variable was created to represent a lifetime
/// bound in a `for` binder. For example, it might have been created to
Expand All @@ -493,6 +496,7 @@ impl NLLRegionVariableOrigin {
NLLRegionVariableOrigin::FreeRegion => true,
NLLRegionVariableOrigin::Placeholder(..) => true,
NLLRegionVariableOrigin::Existential { .. } => false,
NLLRegionVariableOrigin::RootEmptyRegion => false,
}
}

Expand Down
143 changes: 100 additions & 43 deletions src/librustc_mir/borrow_check/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use rustc_data_structures::frozen::Frozen;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::graph::scc::Sccs;
use rustc_hir::def_id::DefId;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::IndexVec;
use rustc_infer::infer::canonical::QueryOutlivesConstraint;
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound};
Expand Down Expand Up @@ -315,16 +314,81 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// SCC could have as well. This implies that the SCC must have
/// the minimum, or narrowest, universe.
fn compute_scc_universes(
constraints_scc: &Sccs<RegionVid, ConstraintSccIndex>,
constraint_sccs: &Sccs<RegionVid, ConstraintSccIndex>,
definitions: &IndexVec<RegionVid, RegionDefinition<'tcx>>,
) -> IndexVec<ConstraintSccIndex, ty::UniverseIndex> {
let num_sccs = constraints_scc.num_sccs();
let num_sccs = constraint_sccs.num_sccs();
let mut scc_universes = IndexVec::from_elem_n(ty::UniverseIndex::MAX, num_sccs);

debug!("compute_scc_universes()");

// For each region R in universe U, ensure that the universe for the SCC
// that contains R is "no bigger" than U. This effectively sets the universe
// for each SCC to be the minimum of the regions within.
for (region_vid, region_definition) in definitions.iter_enumerated() {
let scc = constraints_scc.scc(region_vid);
let scc = constraint_sccs.scc(region_vid);
let scc_universe = &mut scc_universes[scc];
*scc_universe = ::std::cmp::min(*scc_universe, region_definition.universe);
let scc_min = std::cmp::min(region_definition.universe, *scc_universe);
if scc_min != *scc_universe {
*scc_universe = scc_min;
debug!(
"compute_scc_universes: lowered universe of {scc:?} to {scc_min:?} \
because it contains {region_vid:?} in {region_universe:?}",
scc = scc,
scc_min = scc_min,
region_vid = region_vid,
region_universe = region_definition.universe,
);
}
}

// Walk each SCC `A` and `B` such that `A: B`
// and ensure that universe(A) can see universe(B).
//
// This serves to enforce the 'empty/placeholder' hierarchy
// (described in more detail on `RegionKind`):
//
// ```
// static -----+
// | |
// empty(U0) placeholder(U1)
// | /
// empty(U1)
// ```
//
// In particular, imagine we have variables R0 in U0 and R1
// created in U1, and constraints like this;
//
// ```
// R1: !1 // R1 outlives the placeholder in U1
// R1: R0 // R1 outlives R0
// ```
//
// Here, we wish for R1 to be `'static`, because it
// cannot outlive `placeholder(U1)` and `empty(U0)` any other way.
//
// Thanks to this loop, what happens is that the `R1: R0`
// constraint lowers the universe of `R1` to `U0`, which in turn
// means that the `R1: !1` constraint will (later) cause
// `R1` to become `'static`.
for scc_a in constraint_sccs.all_sccs() {
for &scc_b in constraint_sccs.successors(scc_a) {
let scc_universe_a = scc_universes[scc_a];
let scc_universe_b = scc_universes[scc_b];
let scc_universe_min = std::cmp::min(scc_universe_a, scc_universe_b);
if scc_universe_a != scc_universe_min {
scc_universes[scc_a] = scc_universe_min;

debug!(
"compute_scc_universes: lowered universe of {scc_a:?} to {scc_universe_min:?} \
because {scc_a:?}: {scc_b:?} and {scc_b:?} is in universe {scc_universe_b:?}",
scc_a = scc_a,
scc_b = scc_b,
scc_universe_min = scc_universe_min,
scc_universe_b = scc_universe_b
);
}
}
}

debug!("compute_scc_universes: scc_universe = {:#?}", scc_universes);
Expand Down Expand Up @@ -416,7 +480,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
}

NLLRegionVariableOrigin::Existential { .. } => {
NLLRegionVariableOrigin::RootEmptyRegion
| NLLRegionVariableOrigin::Existential { .. } => {
// For existential, regions, nothing to do.
}
}
Expand Down Expand Up @@ -550,47 +615,27 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// SCC. For each SCC, we visit its successors and compute
// their values, then we union all those values to get our
// own.
let visited = &mut BitSet::new_empty(self.constraint_sccs.num_sccs());
for scc_index in self.constraint_sccs.all_sccs() {
self.propagate_constraint_sccs_if_new(scc_index, visited);
let constraint_sccs = self.constraint_sccs.clone();
for scc in constraint_sccs.all_sccs() {
self.compute_value_for_scc(scc);
}

// Sort the applied member constraints so we can binary search
// through them later.
self.member_constraints_applied.sort_by_key(|applied| applied.member_region_scc);
}

/// Computes the value of the SCC `scc_a` if it has not already
/// been computed. The `visited` parameter is a bitset
#[inline]
fn propagate_constraint_sccs_if_new(
&mut self,
scc_a: ConstraintSccIndex,
visited: &mut BitSet<ConstraintSccIndex>,
) {
if visited.insert(scc_a) {
self.propagate_constraint_sccs_new(scc_a, visited);
}
}

/// Computes the value of the SCC `scc_a`, which has not yet been
/// computed. This works by first computing all successors of the
/// SCC (if they haven't been computed already) and then unioning
/// together their elements.
fn propagate_constraint_sccs_new(
&mut self,
scc_a: ConstraintSccIndex,
visited: &mut BitSet<ConstraintSccIndex>,
) {
/// computed, by unioning the values of its successors.
/// Assumes that all successors have been computed already
/// (which is assured by iterating over SCCs in dependency order).
fn compute_value_for_scc(&mut self, scc_a: ConstraintSccIndex) {
let constraint_sccs = self.constraint_sccs.clone();

// Walk each SCC `B` such that `A: B`...
for &scc_b in constraint_sccs.successors(scc_a) {
debug!("propagate_constraint_sccs: scc_a = {:?} scc_b = {:?}", scc_a, scc_b);

// ...compute the value of `B`...
self.propagate_constraint_sccs_if_new(scc_b, visited);

// ...and add elements from `B` into `A`. One complication
// arises because of universes: If `B` contains something
// that `A` cannot name, then `A` can only contain `B` if
Expand Down Expand Up @@ -1258,7 +1303,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
self.check_bound_universal_region(fr, placeholder, errors_buffer);
}

NLLRegionVariableOrigin::Existential { .. } => {
NLLRegionVariableOrigin::RootEmptyRegion
| NLLRegionVariableOrigin::Existential { .. } => {
// nothing to check here
}
}
Expand Down Expand Up @@ -1360,7 +1406,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
self.check_bound_universal_region(fr, placeholder, errors_buffer);
}

NLLRegionVariableOrigin::Existential { .. } => {
NLLRegionVariableOrigin::RootEmptyRegion
| NLLRegionVariableOrigin::Existential { .. } => {
// nothing to check here
}
}
Expand Down Expand Up @@ -1633,9 +1680,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
universe1.cannot_name(placeholder.universe)
}

NLLRegionVariableOrigin::FreeRegion | NLLRegionVariableOrigin::Existential { .. } => {
false
}
NLLRegionVariableOrigin::RootEmptyRegion
| NLLRegionVariableOrigin::FreeRegion
| NLLRegionVariableOrigin::Existential { .. } => false,
}
}

Expand Down Expand Up @@ -1773,6 +1820,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// Finds some region R such that `fr1: R` and `R` is live at `elem`.
crate fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid {
debug!("find_sub_region_live_at(fr1={:?}, elem={:?})", fr1, elem);
debug!("find_sub_region_live_at: {:?} is in scc {:?}", fr1, self.constraint_sccs.scc(fr1));
debug!(
"find_sub_region_live_at: {:?} is in universe {:?}",
fr1,
self.scc_universes[self.constraint_sccs.scc(fr1)]
);
self.find_constraint_paths_between_regions(fr1, |r| {
// First look for some `r` such that `fr1: r` and `r` is live at `elem`
debug!(
Expand All @@ -1794,13 +1847,16 @@ impl<'tcx> RegionInferenceContext<'tcx> {
.or_else(|| {
// If we fail to find THAT, it may be that `fr1` is a
// placeholder that cannot "fit" into its SCC. In that
// case, there should be some `r` where `fr1: r`, both
// `fr1` and `r` are in the same SCC, and `fr1` is a
// case, there should be some `r` where `fr1: r` and `fr1` is a
// placeholder that `r` cannot name. We can blame that
// edge.
//
// Remember that if `R1: R2`, then the universe of R1
// must be able to name the universe of R2, because R2 will
// be at least `'empty(Universe(R2))`, and `R1` must be at
// larger than that.
self.find_constraint_paths_between_regions(fr1, |r| {
self.constraint_sccs.scc(fr1) == self.constraint_sccs.scc(r)
&& self.cannot_name_placeholder(r, fr1)
self.cannot_name_placeholder(r, fr1)
})
})
.map(|(_path, r)| r)
Expand Down Expand Up @@ -1944,7 +2000,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let blame_source = match from_region_origin {
NLLRegionVariableOrigin::FreeRegion
| NLLRegionVariableOrigin::Existential { from_forall: false } => true,
NLLRegionVariableOrigin::Placeholder(_)
NLLRegionVariableOrigin::RootEmptyRegion
| NLLRegionVariableOrigin::Placeholder(_)
| NLLRegionVariableOrigin::Existential { from_forall: true } => false,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,6 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
) {
// FIXME -- this is not the fix I would prefer
if let ty::ReEmpty(ty::UniverseIndex::ROOT) = a {
return;
}
let b = self.to_region_vid(b);
let a = self.to_region_vid(a);
self.add_outlives(b, a);
Expand All @@ -176,10 +172,6 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'
a: ty::Region<'tcx>,
bound: VerifyBound<'tcx>,
) {
// FIXME: I'd prefer if NLL had a notion of empty
if let ty::ReEmpty(ty::UniverseIndex::ROOT) = a {
return;
}
let type_test = self.verify_to_type_test(kind, a, bound);
self.add_type_test(type_test);
}
Expand Down
19 changes: 18 additions & 1 deletion src/librustc_mir/borrow_check/universal_regions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ pub struct UniversalRegions<'tcx> {
/// The total number of universal region variables instantiated.
num_universals: usize,

/// A special region variable created for the `'empty(U0)` region.
/// Note that this is **not** a "universal" region, as it doesn't
/// represent a universally bound placeholder or any such thing.
/// But we do create it here in this type because it's a useful region
/// to have around in a few limited cases.
pub root_empty: RegionVid,

/// The "defining" type for this function, with all universal
/// regions instantiated. For a closure or generator, this is the
/// closure type, but for a top-level function it's the `FnDef`.
Expand Down Expand Up @@ -317,7 +324,11 @@ impl<'tcx> UniversalRegions<'tcx> {

/// See `UniversalRegionIndices::to_region_vid`.
pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
self.indices.to_region_vid(r)
if let ty::ReEmpty(ty::UniverseIndex::ROOT) = r {
self.root_empty
} else {
self.indices.to_region_vid(r)
}
}

/// As part of the NLL unit tests, you can annotate a function with
Expand Down Expand Up @@ -473,10 +484,16 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
_ => None,
};

let root_empty = self
.infcx
.next_nll_region_var(NLLRegionVariableOrigin::RootEmptyRegion)
.to_region_vid();

UniversalRegions {
indices,
fr_static,
fr_fn_body,
root_empty,
first_extern_index,
first_local_index,
num_universals,
Expand Down
Loading