diff --git a/src/Cargo.lock b/src/Cargo.lock index dd21108352792..409bd1ccb0204 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -2136,11 +2136,13 @@ dependencies = [ "flate2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", + "rustc_allocator 0.0.0", "rustc_data_structures 0.0.0", "rustc_incremental 0.0.0", - "rustc_metadata_utils 0.0.0", + "rustc_metadata 0.0.0", "rustc_mir 0.0.0", "rustc_target 0.0.0", + "serialize 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -2283,7 +2285,6 @@ dependencies = [ "rustc 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", - "rustc_metadata_utils 0.0.0", "rustc_target 0.0.0", "serialize 0.0.0", "syntax 0.0.0", @@ -2291,15 +2292,6 @@ dependencies = [ "syntax_pos 0.0.0", ] -[[package]] -name = "rustc_metadata_utils" -version = "0.0.0" -dependencies = [ - "rustc 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", -] - [[package]] name = "rustc_mir" version = "0.0.0" diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index ab3f8fc270720..ff3587d5d8730 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -413,7 +413,7 @@ impl String { /// /// // These are all done without reallocating... /// let cap = s.capacity(); - /// for i in 0..10 { + /// for _ in 0..10 { /// s.push('a'); /// } /// diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 5b6d9e2033caa..2903c370df898 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1857,7 +1857,7 @@ pub trait Iterator { /// ``` /// let a = ["lol", "NaN", "2", "5"]; /// - /// let mut first_number = a.iter().find_map(|s| s.parse().ok()); + /// let first_number = a.iter().find_map(|s| s.parse().ok()); /// /// assert_eq!(first_number, Some(2)); /// ``` diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 4156b1bec92a0..06727d8292d36 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -82,6 +82,7 @@ #![feature(const_fn)] #![feature(const_int_ops)] #![feature(const_fn_union)] +#![feature(const_manually_drop_new)] #![feature(custom_attribute)] #![feature(doc_cfg)] #![feature(doc_spotlight)] diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 27ee9556bd089..a955e0e662a6c 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1021,6 +1021,15 @@ pub union MaybeUninit { } impl MaybeUninit { + /// Create a new `MaybeUninit` initialized with the given value. + /// + /// Note that dropping a `MaybeUninit` will never call `T`'s drop code. + /// It is your responsibility to make sure `T` gets dropped if it got initialized. + #[unstable(feature = "maybe_uninit", issue = "53491")] + pub const fn new(val: T) -> MaybeUninit { + MaybeUninit { value: ManuallyDrop::new(val) } + } + /// Create a new `MaybeUninit` in an uninitialized state. /// /// Note that dropping a `MaybeUninit` will never call `T`'s drop code. diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 0c38cb10a2320..c181235628338 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -100,9 +100,6 @@ for ty::RegionKind { ty::ReEmpty => { // No variant fields to hash for these ... } - ty::ReCanonical(c) => { - c.hash_stable(hcx, hasher); - } ty::ReLateBound(db, ty::BrAnon(i)) => { db.hash_stable(hcx, hasher); i.hash_stable(hcx, hasher); @@ -147,7 +144,7 @@ impl<'a> HashStable> for ty::RegionVid { } } -impl<'gcx> HashStable> for ty::BoundTyIndex { +impl<'gcx> HashStable> for ty::BoundVar { #[inline] fn hash_stable(&self, hcx: &mut StableHashingContext<'gcx>, @@ -894,6 +891,9 @@ for ty::TyKind<'gcx> Param(param_ty) => { param_ty.hash_stable(hcx, hasher); } + Bound(bound_ty) => { + bound_ty.hash_stable(hcx, hasher); + } Foreign(def_id) => { def_id.hash_stable(hcx, hasher); } @@ -911,7 +911,6 @@ impl_stable_hash_for!(enum ty::InferTy { FreshTy(a), FreshIntTy(a), FreshFloatTy(a), - BoundTy(a), }); impl<'a, 'gcx> HashStable> diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index 2b085a3407ccc..e969e10f1b3c8 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -23,7 +23,7 @@ use infer::InferCtxt; use std::sync::atomic::Ordering; use ty::fold::{TypeFoldable, TypeFolder}; use ty::subst::Kind; -use ty::{self, BoundTy, BoundTyIndex, Lift, List, Ty, TyCtxt, TypeFlags}; +use ty::{self, BoundTy, BoundVar, Lift, List, Ty, TyCtxt, TypeFlags}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; @@ -225,9 +225,11 @@ struct Canonicalizer<'cx, 'gcx: 'tcx, 'tcx: 'cx> { query_state: &'cx mut OriginalQueryValues<'tcx>, // Note that indices is only used once `var_values` is big enough to be // heap-allocated. - indices: FxHashMap, BoundTyIndex>, + indices: FxHashMap, BoundVar>, canonicalize_region_mode: &'cx dyn CanonicalizeRegionMode, needs_canonical_flags: TypeFlags, + + binder_index: ty::DebruijnIndex, } impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> { @@ -235,11 +237,23 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> self.tcx } + fn fold_binder(&mut self, t: &ty::Binder) -> ty::Binder + where T: TypeFoldable<'tcx> + { + self.binder_index.shift_in(1); + let t = t.super_fold_with(self); + self.binder_index.shift_out(1); + t + } + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { - ty::ReLateBound(..) => { - // leave bound regions alone - r + ty::ReLateBound(index, ..) => { + if index >= self.binder_index { + bug!("escaping late bound region during canonicalization") + } else { + r + } } ty::ReVar(vid) => { @@ -263,8 +277,8 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> | ty::ReEmpty | ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r), - ty::ReClosureBound(..) | ty::ReCanonical(_) => { - bug!("canonical region encountered during canonicalization") + ty::ReClosureBound(..) => { + bug!("closure bound region encountered during canonicalization") } } } @@ -283,8 +297,12 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> bug!("encountered a fresh type during canonicalization") } - ty::Infer(ty::BoundTy(_)) => { - bug!("encountered a canonical type during canonicalization") + ty::Bound(bound_ty) => { + if bound_ty.index >= self.binder_index { + bug!("escaping bound type during canonicalization") + } else { + t + } } ty::Closure(..) @@ -335,12 +353,6 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { where V: TypeFoldable<'tcx> + Lift<'gcx>, { - debug_assert!( - !value.has_type_flags(TypeFlags::HAS_CANONICAL_VARS), - "canonicalizing a canonical value: {:?}", - value, - ); - let needs_canonical_flags = if canonicalize_region_mode.any() { TypeFlags::HAS_FREE_REGIONS | TypeFlags::KEEP_IN_LOCAL_TCX } else { @@ -367,6 +379,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { variables: SmallVec::new(), query_state, indices: FxHashMap::default(), + binder_index: ty::INNERMOST, }; let out_value = value.fold_with(&mut canonicalizer); @@ -393,7 +406,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { /// or returns an existing variable if `kind` has already been /// seen. `kind` is expected to be an unbound variable (or /// potentially a free region). - fn canonical_var(&mut self, info: CanonicalVarInfo, kind: Kind<'tcx>) -> BoundTy { + fn canonical_var(&mut self, info: CanonicalVarInfo, kind: Kind<'tcx>) -> BoundVar { let Canonicalizer { variables, query_state, @@ -413,7 +426,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { // direct linear search of `var_values`. if let Some(idx) = var_values.iter().position(|&k| k == kind) { // `kind` is already present in `var_values`. - BoundTyIndex::new(idx) + BoundVar::new(idx) } else { // `kind` isn't present in `var_values`. Append it. Likewise // for `info` and `variables`. @@ -428,11 +441,11 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { *indices = var_values .iter() .enumerate() - .map(|(i, &kind)| (kind, BoundTyIndex::new(i))) + .map(|(i, &kind)| (kind, BoundVar::new(i))) .collect(); } // The cv is the index of the appended element. - BoundTyIndex::new(var_values.len() - 1) + BoundVar::new(var_values.len() - 1) } } else { // `var_values` is large. Do a hashmap search via `indices`. @@ -440,23 +453,23 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { variables.push(info); var_values.push(kind); assert_eq!(variables.len(), var_values.len()); - BoundTyIndex::new(variables.len() - 1) + BoundVar::new(variables.len() - 1) }) }; - BoundTy { - level: ty::INNERMOST, - var, - } + var } fn canonical_var_for_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { let info = CanonicalVarInfo { kind: CanonicalVarKind::Region, }; - let b = self.canonical_var(info, r.into()); - debug_assert_eq!(ty::INNERMOST, b.level); - self.tcx().mk_region(ty::ReCanonical(b.var)) + let var = self.canonical_var(info, r.into()); + let region = ty::ReLateBound( + self.binder_index, + ty::BoundRegion::BrAnon(var.as_u32()) + ); + self.tcx().mk_region(region) } /// Given a type variable `ty_var` of the given kind, first check @@ -472,9 +485,8 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { let info = CanonicalVarInfo { kind: CanonicalVarKind::Ty(ty_kind), }; - let b = self.canonical_var(info, ty_var.into()); - debug_assert_eq!(ty::INNERMOST, b.level); - self.tcx().mk_infer(ty::InferTy::BoundTy(b)) + let var = self.canonical_var(info, ty_var.into()); + self.tcx().mk_ty(ty::Bound(BoundTy::new(self.binder_index, var))) } } } diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs index e3bd407d17a90..696220691e141 100644 --- a/src/librustc/infer/canonical/mod.rs +++ b/src/librustc/infer/canonical/mod.rs @@ -20,7 +20,7 @@ //! - a map M (of type `CanonicalVarValues`) from those canonical //! variables back to the original. //! -//! We can then do queries using T2. These will give back constriants +//! We can then do queries using T2. These will give back constraints //! on the canonical variables which can be translated, using the map //! M, into constraints in our source context. This process of //! translating the results back is done by the @@ -40,7 +40,7 @@ use std::ops::Index; use syntax::source_map::Span; use ty::fold::TypeFoldable; use ty::subst::Kind; -use ty::{self, BoundTyIndex, Lift, Region, List, TyCtxt}; +use ty::{self, BoundVar, Lift, Region, List, TyCtxt}; mod canonicalizer; @@ -72,7 +72,7 @@ impl<'gcx> UseSpecializedDecodable for CanonicalVarInfos<'gcx> {} /// canonicalized query response. #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] pub struct CanonicalVarValues<'tcx> { - pub var_values: IndexVec>, + pub var_values: IndexVec>, } /// When we canonicalize a value to form a query, we wind up replacing @@ -264,7 +264,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { span: Span, variables: &List, ) -> CanonicalVarValues<'tcx> { - let var_values: IndexVec> = variables + let var_values: IndexVec> = variables .iter() .map(|info| self.fresh_inference_var_for_canonical_var(span, *info)) .collect(); @@ -367,10 +367,10 @@ BraceStructLiftImpl! { } where R: Lift<'tcx> } -impl<'tcx> Index for CanonicalVarValues<'tcx> { +impl<'tcx> Index for CanonicalVarValues<'tcx> { type Output = Kind<'tcx>; - fn index(&self, value: BoundTyIndex) -> &Kind<'tcx> { + fn index(&self, value: BoundVar) -> &Kind<'tcx> { &self.var_values[value] } } diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs index 38788186eb071..bf86fc99afee3 100644 --- a/src/librustc/infer/canonical/query_response.rs +++ b/src/librustc/infer/canonical/query_response.rs @@ -35,7 +35,7 @@ use traits::{FulfillmentContext, TraitEngine}; use traits::{Obligation, ObligationCause, PredicateObligation}; use ty::fold::TypeFoldable; use ty::subst::{Kind, UnpackedKind}; -use ty::{self, BoundTyIndex, Lift, Ty, TyCtxt}; +use ty::{self, BoundVar, Lift, Ty, TyCtxt}; impl<'cx, 'gcx, 'tcx> InferCtxtBuilder<'cx, 'gcx, 'tcx> { /// The "main method" for a canonicalized trait query. Given the @@ -273,7 +273,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { for (index, original_value) in original_values.var_values.iter().enumerate() { // ...with the value `v_r` of that variable from the query. let result_value = query_response.substitute_projected(self.tcx, &result_subst, |v| { - &v.var_values[BoundTyIndex::new(index)] + &v.var_values[BoundVar::new(index)] }); match (original_value.unpack(), result_value.unpack()) { (UnpackedKind::Lifetime(ty::ReErased), UnpackedKind::Lifetime(ty::ReErased)) => { @@ -308,11 +308,14 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { // ...also include the other query region constraints from the query. output_query_region_constraints.extend( query_response.value.region_constraints.iter().filter_map(|r_c| { - let &ty::OutlivesPredicate(k1, r2) = r_c.skip_binder(); // reconstructed below - let k1 = substitute_value(self.tcx, &result_subst, &k1); - let r2 = substitute_value(self.tcx, &result_subst, &r2); + let r_c = substitute_value(self.tcx, &result_subst, r_c); + + // Screen out `'a: 'a` cases -- we skip the binder here but + // only care the inner values to one another, so they are still at + // consistent binding levels. + let &ty::OutlivesPredicate(k1, r2) = r_c.skip_binder(); if k1 != r2.into() { - Some(ty::Binder::bind(ty::OutlivesPredicate(k1, r2))) + Some(r_c) } else { None } @@ -408,7 +411,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { // is directly equal to one of the canonical variables in the // result, then we can type the corresponding value from the // input. See the example above. - let mut opt_values: IndexVec>> = + let mut opt_values: IndexVec>> = IndexVec::from_elem_n(None, query_response.variables.len()); // In terms of our example above, we are iterating over pairs like: @@ -417,16 +420,22 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { match result_value.unpack() { UnpackedKind::Type(result_value) => { // e.g., here `result_value` might be `?0` in the example above... - if let ty::Infer(ty::InferTy::BoundTy(b)) = result_value.sty { - // in which case we would set `canonical_vars[0]` to `Some(?U)`. + if let ty::Bound(b) = result_value.sty { + // ...in which case we would set `canonical_vars[0]` to `Some(?U)`. + + // We only allow a `ty::INNERMOST` index in substitutions. + assert_eq!(b.index, ty::INNERMOST); opt_values[b.var] = Some(*original_value); } } UnpackedKind::Lifetime(result_value) => { // e.g., here `result_value` might be `'?1` in the example above... - if let &ty::RegionKind::ReCanonical(index) = result_value { - // in which case we would set `canonical_vars[0]` to `Some('static)`. - opt_values[index] = Some(*original_value); + if let &ty::RegionKind::ReLateBound(index, br) = result_value { + // ... in which case we would set `canonical_vars[0]` to `Some('static)`. + + // We only allow a `ty::INNERMOST` index in substitutions. + assert_eq!(index, ty::INNERMOST); + opt_values[br.assert_bound_var()] = Some(*original_value); } } } @@ -440,7 +449,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { .variables .iter() .enumerate() - .map(|(index, info)| opt_values[BoundTyIndex::new(index)].unwrap_or_else(|| + .map(|(index, info)| opt_values[BoundVar::new(index)].unwrap_or_else(|| self.fresh_inference_var_for_canonical_var(cause.span, *info) )) .collect(), @@ -470,7 +479,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { // canonical variable; this is taken from // `query_response.var_values` after applying the substitution // `result_subst`. - let substituted_query_response = |index: BoundTyIndex| -> Kind<'tcx> { + let substituted_query_response = |index: BoundVar| -> Kind<'tcx> { query_response.substitute_projected(self.tcx, &result_subst, |v| &v.var_values[index]) }; @@ -497,22 +506,23 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { unsubstituted_region_constraints .iter() .map(move |constraint| { - let ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below - let k1 = substitute_value(self.tcx, result_subst, k1); - let r2 = substitute_value(self.tcx, result_subst, r2); + let constraint = substitute_value(self.tcx, result_subst, constraint); + let &ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below Obligation::new( cause.clone(), param_env, match k1.unpack() { UnpackedKind::Lifetime(r1) => ty::Predicate::RegionOutlives( - ty::Binder::dummy( + ty::Binder::bind( ty::OutlivesPredicate(r1, r2) - )), + ) + ), UnpackedKind::Type(t1) => ty::Predicate::TypeOutlives( - ty::Binder::dummy(ty::OutlivesPredicate( - t1, r2 - ))) + ty::Binder::bind( + ty::OutlivesPredicate(t1, r2) + ) + ), } ) }) @@ -526,12 +536,12 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, variables1: &OriginalQueryValues<'tcx>, - variables2: impl Fn(BoundTyIndex) -> Kind<'tcx>, + variables2: impl Fn(BoundVar) -> Kind<'tcx>, ) -> InferResult<'tcx, ()> { self.commit_if_ok(|_| { let mut obligations = vec![]; for (index, value1) in variables1.var_values.iter().enumerate() { - let value2 = variables2(BoundTyIndex::new(index)); + let value2 = variables2(BoundVar::new(index)); match (value1.unpack(), value2.unpack()) { (UnpackedKind::Type(v1), UnpackedKind::Type(v2)) => { @@ -594,11 +604,11 @@ pub fn make_query_outlives<'tcx>( } Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1), }) - .map(ty::Binder::dummy) // no bound regions in the code above + .map(ty::Binder::dummy) // no bound vars in the code above .chain( outlives_obligations .map(|(ty, r)| ty::OutlivesPredicate(ty.into(), r)) - .map(ty::Binder::dummy), // no bound regions in the code above + .map(ty::Binder::dummy) // no bound vars in the code above ) .collect(); diff --git a/src/librustc/infer/canonical/substitute.rs b/src/librustc/infer/canonical/substitute.rs index 03441c3dee35e..b8c1ed236c0ba 100644 --- a/src/librustc/infer/canonical/substitute.rs +++ b/src/librustc/infer/canonical/substitute.rs @@ -17,9 +17,9 @@ //! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html use infer::canonical::{Canonical, CanonicalVarValues}; -use ty::fold::{TypeFoldable, TypeFolder}; +use ty::fold::TypeFoldable; use ty::subst::UnpackedKind; -use ty::{self, Ty, TyCtxt, TypeFlags}; +use ty::{self, TyCtxt}; impl<'tcx, V> Canonical<'tcx, V> { /// Instantiate the wrapped value, replacing each canonical value @@ -64,51 +64,22 @@ where T: TypeFoldable<'tcx>, { if var_values.var_values.is_empty() { - debug_assert!(!value.has_type_flags(TypeFlags::HAS_CANONICAL_VARS)); - value.clone() - } else if !value.has_type_flags(TypeFlags::HAS_CANONICAL_VARS) { value.clone() } else { - value.fold_with(&mut CanonicalVarValuesSubst { tcx, var_values }) - } -} - -struct CanonicalVarValuesSubst<'cx, 'gcx: 'tcx, 'tcx: 'cx> { - tcx: TyCtxt<'cx, 'gcx, 'tcx>, - var_values: &'cx CanonicalVarValues<'tcx>, -} - -impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for CanonicalVarValuesSubst<'cx, 'gcx, 'tcx> { - fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> { - self.tcx - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match t.sty { - ty::Infer(ty::InferTy::BoundTy(b)) => { - debug_assert_eq!(ty::INNERMOST, b.level); - match self.var_values.var_values[b.var].unpack() { - UnpackedKind::Type(ty) => ty, - r => bug!("{:?} is a type but value is {:?}", b, r), - } + let fld_r = |br: ty::BoundRegion| { + match var_values.var_values[br.assert_bound_var()].unpack() { + UnpackedKind::Lifetime(l) => l, + r => bug!("{:?} is a region but value is {:?}", br, r), } - _ => { - if !t.has_type_flags(TypeFlags::HAS_CANONICAL_VARS) { - t - } else { - t.super_fold_with(self) - } + }; + + let fld_t = |bound_ty: ty::BoundTy| { + match var_values.var_values[bound_ty.var].unpack() { + UnpackedKind::Type(ty) => ty, + r => bug!("{:?} is a type but value is {:?}", bound_ty, r), } - } - } + }; - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match r { - ty::RegionKind::ReCanonical(c) => match self.var_values.var_values[*c].unpack() { - UnpackedKind::Lifetime(l) => l, - r => bug!("{:?} is a region but value is {:?}", c, r), - }, - _ => r.super_fold_with(self), - } + tcx.replace_escaping_bound_vars(value, fld_r, fld_t) } } diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 0ee03bc4c6e00..f13210926a79b 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -485,7 +485,6 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, ' } } - ty::ReCanonical(..) | ty::ReClosureBound(..) => { span_bug!( self.span, diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 8b4669c89fe83..d457cda86c0af 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -152,7 +152,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } // We shouldn't encounter an error message with ReClosureBound. - ty::ReCanonical(..) | ty::ReClosureBound(..) => { + ty::ReClosureBound(..) => { bug!("encountered unexpected ReClosureBound: {:?}", region,); } }; diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 1647f259db9fb..b53444992fa21 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -114,7 +114,6 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { self.tcx().types.re_erased } - ty::ReCanonical(..) | ty::ReClosureBound(..) => { bug!( "encountered unexpected region: {:?}", @@ -171,8 +170,8 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { t } - ty::Infer(ty::BoundTy(..)) => - bug!("encountered canonical ty during freshening"), + ty::Bound(..) => + bug!("encountered bound ty during freshening"), ty::Generator(..) | ty::Bool | diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs index 8f28e9a320df2..75f503d3bcfb4 100644 --- a/src/librustc/infer/lexical_region_resolve/mod.rs +++ b/src/librustc/infer/lexical_region_resolve/mod.rs @@ -260,9 +260,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> { let tcx = self.tcx(); match (a, b) { - (&ty::ReCanonical(..), _) - | (_, &ty::ReCanonical(..)) - | (&ty::ReClosureBound(..), _) + (&ty::ReClosureBound(..), _) | (_, &ty::ReClosureBound(..)) | (&ReLateBound(..), _) | (_, &ReLateBound(..)) diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc/infer/outlives/obligations.rs index 5db850f1588b6..523f03c2cfc47 100644 --- a/src/librustc/infer/outlives/obligations.rs +++ b/src/librustc/infer/outlives/obligations.rs @@ -305,7 +305,7 @@ where ty, region, origin ); - assert!(!ty.has_escaping_regions()); + assert!(!ty.has_escaping_bound_vars()); let components = self.tcx.outlives_components(ty); self.components_must_outlive(origin, components, region); diff --git a/src/librustc/infer/outlives/verify.rs b/src/librustc/infer/outlives/verify.rs index e1db295b7e14d..88d45671b9afd 100644 --- a/src/librustc/infer/outlives/verify.rs +++ b/src/librustc/infer/outlives/verify.rs @@ -323,7 +323,7 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> { predicates .into_iter() .filter_map(|p| p.as_ref().to_opt_type_outlives()) - .filter_map(|p| p.no_late_bound_regions()) + .filter_map(|p| p.no_bound_vars()) .filter(move |p| compare_ty(p.0)) } } diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs index c82603bf56057..46b12d01829e7 100644 --- a/src/librustc/infer/region_constraints/mod.rs +++ b/src/librustc/infer/region_constraints/mod.rs @@ -833,10 +833,6 @@ impl<'tcx> RegionConstraintCollector<'tcx> { ty::RePlaceholder(placeholder) => placeholder.universe, ty::ReClosureBound(vid) | ty::ReVar(vid) => self.var_universe(vid), ty::ReLateBound(..) => bug!("universe(): encountered bound region {:?}", region), - ty::ReCanonical(..) => bug!( - "region_universe(): encountered canonical region {:?}", - region - ), } } diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index 048810c042722..3b0f9a5e545fd 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -84,8 +84,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> // Shouldn't have any LBR here, so we can safely put // this under a binder below without fear of accidental // capture. - assert!(!a.has_escaping_regions()); - assert!(!b.has_escaping_regions()); + assert!(!a.has_escaping_bound_vars()); + assert!(!b.has_escaping_bound_vars()); // can't make progress on `A <: B` if both A and B are // type variables, so record an obligation. We also diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index 6a4f734674563..732b32cc35d68 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -21,6 +21,7 @@ use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, use session::Session; use syntax::ast; use syntax::attr; +use syntax::feature_gate; use syntax::source_map::MultiSpan; use syntax::symbol::Symbol; use util::nodemap::FxHashMap; @@ -199,8 +200,7 @@ impl<'a> LintLevelsBuilder<'a> { let store = self.sess.lint_store.borrow(); let sess = self.sess; let bad_attr = |span| { - span_err!(sess, span, E0452, - "malformed lint attribute"); + struct_span_err!(sess, span, E0452, "malformed lint attribute") }; for attr in attrs { let level = match Level::from_str(&attr.name().as_str()) { @@ -211,19 +211,76 @@ impl<'a> LintLevelsBuilder<'a> { let meta = unwrap_or!(attr.meta(), continue); attr::mark_used(attr); - let metas = if let Some(metas) = meta.meta_item_list() { + let mut metas = if let Some(metas) = meta.meta_item_list() { metas } else { - bad_attr(meta.span); - continue + let mut err = bad_attr(meta.span); + err.emit(); + continue; }; + if metas.is_empty() { + // FIXME (#55112): issue unused-attributes lint for `#[level()]` + continue; + } + + // Before processing the lint names, look for a reason (RFC 2383) + // at the end. + let mut reason = None; + let tail_li = &metas[metas.len()-1]; + if let Some(item) = tail_li.meta_item() { + match item.node { + ast::MetaItemKind::Word => {} // actual lint names handled later + ast::MetaItemKind::NameValue(ref name_value) => { + let gate_reasons = !self.sess.features_untracked().lint_reasons; + if item.ident == "reason" { + // found reason, reslice meta list to exclude it + metas = &metas[0..metas.len()-1]; + // FIXME (#55112): issue unused-attributes lint if we thereby + // don't have any lint names (`#[level(reason = "foo")]`) + if let ast::LitKind::Str(rationale, _) = name_value.node { + if gate_reasons { + feature_gate::emit_feature_err( + &self.sess.parse_sess, + "lint_reasons", + item.span, + feature_gate::GateIssue::Language, + "lint reasons are experimental" + ); + } else { + reason = Some(rationale); + } + } else { + let mut err = bad_attr(name_value.span); + err.help("reason must be a string literal"); + err.emit(); + } + } else { + let mut err = bad_attr(item.span); + err.emit(); + } + }, + ast::MetaItemKind::List(_) => { + let mut err = bad_attr(item.span); + err.emit(); + } + } + } + for li in metas { let word = match li.word() { Some(word) => word, None => { - bad_attr(li.span); - continue + let mut err = bad_attr(li.span); + if let Some(item) = li.meta_item() { + if let ast::MetaItemKind::NameValue(_) = item.node { + if item.ident == "reason" { + err.help("reason in lint attribute must come last"); + } + } + } + err.emit(); + continue; } }; let tool_name = if let Some(lint_tool) = word.is_scoped() { @@ -245,7 +302,7 @@ impl<'a> LintLevelsBuilder<'a> { let name = word.name(); match store.check_lint_name(&name.as_str(), tool_name) { CheckLintNameResult::Ok(ids) => { - let src = LintSource::Node(name, li.span); + let src = LintSource::Node(name, li.span, reason); for id in ids { specs.insert(*id, (level, src)); } @@ -255,7 +312,9 @@ impl<'a> LintLevelsBuilder<'a> { match result { Ok(ids) => { let complete_name = &format!("{}::{}", tool_name.unwrap(), name); - let src = LintSource::Node(Symbol::intern(complete_name), li.span); + let src = LintSource::Node( + Symbol::intern(complete_name), li.span, reason + ); for id in ids { specs.insert(*id, (level, src)); } @@ -286,7 +345,9 @@ impl<'a> LintLevelsBuilder<'a> { Applicability::MachineApplicable, ).emit(); - let src = LintSource::Node(Symbol::intern(&new_lint_name), li.span); + let src = LintSource::Node( + Symbol::intern(&new_lint_name), li.span, reason + ); for id in ids { specs.insert(*id, (level, src)); } @@ -368,11 +429,11 @@ impl<'a> LintLevelsBuilder<'a> { }; let forbidden_lint_name = match forbid_src { LintSource::Default => id.to_string(), - LintSource::Node(name, _) => name.to_string(), + LintSource::Node(name, _, _) => name.to_string(), LintSource::CommandLine(name) => name.to_string(), }; let (lint_attr_name, lint_attr_span) = match *src { - LintSource::Node(name, span) => (name, span), + LintSource::Node(name, span, _) => (name, span), _ => continue, }; let mut diag_builder = struct_span_err!(self.sess, @@ -384,15 +445,19 @@ impl<'a> LintLevelsBuilder<'a> { forbidden_lint_name); diag_builder.span_label(lint_attr_span, "overruled by previous forbid"); match forbid_src { - LintSource::Default => &mut diag_builder, - LintSource::Node(_, forbid_source_span) => { + LintSource::Default => {}, + LintSource::Node(_, forbid_source_span, reason) => { diag_builder.span_label(forbid_source_span, - "`forbid` level set here") + "`forbid` level set here"); + if let Some(rationale) = reason { + diag_builder.note(&rationale.as_str()); + } }, LintSource::CommandLine(_) => { - diag_builder.note("`forbid` lint level was set on command line") + diag_builder.note("`forbid` lint level was set on command line"); } - }.emit(); + } + diag_builder.emit(); // don't set a separate error for every lint in the group break } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 5ac0c0d32dcdc..afd7800810982 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -470,7 +470,7 @@ pub enum LintSource { Default, /// Lint level was set by an attribute. - Node(ast::Name, Span), + Node(ast::Name, Span, Option /* RFC 2383 reason */), /// Lint level was set by a command-line flag. CommandLine(Symbol), @@ -478,7 +478,7 @@ pub enum LintSource { impl_stable_hash_for!(enum self::LintSource { Default, - Node(name, span), + Node(name, span, reason), CommandLine(text) }); @@ -578,7 +578,10 @@ pub fn struct_lint_level<'a>(sess: &'a Session, hyphen_case_flag_val)); } } - LintSource::Node(lint_attr_name, src) => { + LintSource::Node(lint_attr_name, src, reason) => { + if let Some(rationale) = reason { + err.note(&rationale.as_str()); + } sess.diag_span_note_once(&mut err, DiagnosticMessageId::from(lint), src, "lint level defined here"); if lint_attr_name.as_str() != name { diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs index 50ca6ca78ab3a..e87e425762d56 100644 --- a/src/librustc/traits/auto_trait.rs +++ b/src/librustc/traits/auto_trait.rs @@ -683,8 +683,8 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { } &ty::Predicate::TypeOutlives(ref binder) => { match ( - binder.no_late_bound_regions(), - binder.map_bound_ref(|pred| pred.0).no_late_bound_regions(), + binder.no_bound_vars(), + binder.map_bound_ref(|pred| pred.0).no_bound_vars(), ) { (None, Some(t_a)) => { select.infcx().register_region_obligation_with_cause( diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 817e9ffcbb55d..71b77909b82a8 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -455,7 +455,7 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool { false } - ty::Infer(..) => match in_crate { + ty::Bound(..) | ty::Infer(..) => match in_crate { InCrate::Local => false, // The inference variable might be unified with a local // type in that remote crate. diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 15a0adc3c0692..567fe667a0406 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -281,7 +281,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::Generator(..) => Some(18), ty::Foreign(..) => Some(19), ty::GeneratorWitness(..) => Some(20), - ty::Infer(..) | ty::Error => None, + ty::Bound(..) | ty::Infer(..) | ty::Error => None, ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), } } diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index cfa77b210e857..aea956461f27b 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -143,7 +143,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { debug!("normalize_projection_type(projection_ty={:?})", projection_ty); - debug_assert!(!projection_ty.has_escaping_regions()); + debug_assert!(!projection_ty.has_escaping_bound_vars()); // FIXME(#20304) -- cache @@ -349,15 +349,15 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, } ty::Predicate::TypeOutlives(ref binder) => { - // Check if there are higher-ranked regions. - match binder.no_late_bound_regions() { + // Check if there are higher-ranked vars. + match binder.no_bound_vars() { // If there are, inspect the underlying type further. None => { // Convert from `Binder>` to `Binder`. let binder = binder.map_bound_ref(|pred| pred.0); - // Check if the type has any bound regions. - match binder.no_late_bound_regions() { + // Check if the type has any bound vars. + match binder.no_bound_vars() { // If so, this obligation is an error (for now). Eventually we should be // able to support additional cases here, like `for<'a> &'a str: 'a`. // NOTE: this is duplicate-implemented between here and fulfillment. diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 6b2ec64668e9b..5e2f1fe08b90e 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -352,7 +352,7 @@ impl<'tcx> GoalKind<'tcx> { domain_goal: PolyDomainGoal<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, ) -> GoalKind<'tcx> { - match domain_goal.no_late_bound_regions() { + match domain_goal.no_bound_vars() { Some(p) => p.into_goal(), None => GoalKind::Quantified( QuantifierKind::Universal, diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 4eda47d31ebb5..80358294d056c 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -366,7 +366,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, let ty = ty.super_fold_with(self); match ty.sty { - ty::Opaque(def_id, substs) if !substs.has_escaping_regions() => { // (*) + ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { // (*) // Only normalize `impl Trait` after type-checking, usually in codegen. match self.param_env.reveal { Reveal::UserFacing => ty, @@ -393,7 +393,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, } } - ty::Projection(ref data) if !data.has_escaping_regions() => { // (*) + ty::Projection(ref data) if !data.has_escaping_bound_vars() => { // (*) // (*) This is kind of hacky -- we need to be able to // handle normalization within binders because @@ -1619,7 +1619,7 @@ impl<'cx, 'gcx, 'tcx> ProjectionCacheKey<'tcx> { let infcx = selcx.infcx(); // We don't do cross-snapshot caching of obligations with escaping regions, // so there's no cache key to use - predicate.no_late_bound_regions() + predicate.no_bound_vars() .map(|predicate| ProjectionCacheKey { // We don't attempt to match up with a specific type-variable state // from a specific call to `opt_normalize_projection_type` - if diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs index 8f7b0df8b95aa..62317f074764f 100644 --- a/src/librustc/traits/query/dropck_outlives.rs +++ b/src/librustc/traits/query/dropck_outlives.rs @@ -252,6 +252,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> | ty::Param(_) | ty::Opaque(..) | ty::Infer(_) + | ty::Bound(..) | ty::Generator(..) => false, ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs index 4adb65dc58d91..59b086e35de31 100644 --- a/src/librustc/traits/query/normalize.rs +++ b/src/librustc/traits/query/normalize.rs @@ -100,7 +100,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { let ty = ty.super_fold_with(self); match ty.sty { - ty::Opaque(def_id, substs) if !substs.has_escaping_regions() => { + ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { // (*) // Only normalize `impl Trait` after type-checking, usually in codegen. match self.param_env.reveal { @@ -138,7 +138,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx } } - ty::Projection(ref data) if !data.has_escaping_regions() => { + ty::Projection(ref data) if !data.has_escaping_bound_vars() => { // (*) // (*) This is kind of hacky -- we need to be able to // handle normalization within binders because diff --git a/src/librustc/traits/query/outlives_bounds.rs b/src/librustc/traits/query/outlives_bounds.rs index 99f557d44d9aa..b3fae3bab3471 100644 --- a/src/librustc/traits/query/outlives_bounds.rs +++ b/src/librustc/traits/query/outlives_bounds.rs @@ -164,7 +164,7 @@ pub fn explicit_outlives_bounds<'tcx>( ty::Predicate::ClosureKind(..) | ty::Predicate::TypeOutlives(..) | ty::Predicate::ConstEvaluatable(..) => None, - ty::Predicate::RegionOutlives(ref data) => data.no_late_bound_regions().map( + ty::Predicate::RegionOutlives(ref data) => data.no_bound_vars().map( |ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a), ), }) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 2ea16823cc65d..5a60c784b1439 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -587,7 +587,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation: &TraitObligation<'tcx>, ) -> SelectionResult<'tcx, Selection<'tcx>> { debug!("select({:?})", obligation); - debug_assert!(!obligation.predicate.has_escaping_regions()); + debug_assert!(!obligation.predicate.has_escaping_bound_vars()); let stack = self.push_stack(TraitObligationStackList::empty(), obligation); @@ -690,7 +690,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { match obligation.predicate { ty::Predicate::Trait(ref t) => { - debug_assert!(!t.has_escaping_regions()); + debug_assert!(!t.has_escaping_bound_vars()); let obligation = obligation.with(t.clone()); self.evaluate_trait_predicate_recursively(previous_stack, obligation) } @@ -722,9 +722,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { }, ty::Predicate::TypeOutlives(ref binder) => { - assert!(!binder.has_escaping_regions()); - // Check if the type has higher-ranked regions. - if binder.skip_binder().0.has_escaping_regions() { + assert!(!binder.has_escaping_bound_vars()); + // Check if the type has higher-ranked vars. + if binder.skip_binder().0.has_escaping_bound_vars() { // If so, this obligation is an error (for now). Eventually we should be // able to support additional cases here, like `for<'a> &'a str: 'a`. @@ -740,7 +740,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Ok(EvaluatedToErr) } } else { - // If the type has no late bound regions, then if we assign all + // If the type has no late bound vars, then if we assign all // the inference variables in it to be 'static, then the type // will be 'static itself. // @@ -1199,7 +1199,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { "candidate_from_obligation(cache_fresh_trait_pred={:?}, obligation={:?})", cache_fresh_trait_pred, stack ); - debug_assert!(!stack.obligation.predicate.has_escaping_regions()); + debug_assert!(!stack.obligation.predicate.has_escaping_bound_vars()); if let Some(c) = self.check_candidate_cache(stack.obligation.param_env, &cache_fresh_trait_pred) @@ -1800,7 +1800,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { placeholder_map: &infer::PlaceholderMap<'tcx>, snapshot: &infer::CombinedSnapshot<'cx, 'tcx>, ) -> bool { - debug_assert!(!skol_trait_ref.has_escaping_regions()); + debug_assert!(!skol_trait_ref.has_escaping_bound_vars()); if self.infcx .at(&obligation.cause, obligation.param_env) .sup(ty::Binder::dummy(skol_trait_ref), trait_bound) @@ -2179,7 +2179,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // T: Trait // so it seems ok if we (conservatively) fail to accept that `Unsize` // obligation above. Should be possible to extend this in the future. - let source = match obligation.self_ty().no_late_bound_regions() { + let source = match obligation.self_ty().no_bound_vars() { Some(t) => t, None => { // Don't add any candidates if there are bound regions. @@ -2456,7 +2456,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::Infer(ty::TyVar(_)) => Ambiguous, ty::UnnormalizedProjection(..) - | ty::Infer(ty::BoundTy(_)) + | ty::Bound(_) | ty::Infer(ty::FreshTy(_)) | ty::Infer(ty::FreshIntTy(_)) | ty::Infer(ty::FreshFloatTy(_)) => { @@ -2541,7 +2541,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } ty::UnnormalizedProjection(..) - | ty::Infer(ty::BoundTy(_)) + | ty::Bound(_) | ty::Infer(ty::FreshTy(_)) | ty::Infer(ty::FreshIntTy(_)) | ty::Infer(ty::FreshFloatTy(_)) => { @@ -2584,7 +2584,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { | ty::Param(..) | ty::Foreign(..) | ty::Projection(..) - | ty::Infer(ty::BoundTy(_)) + | ty::Bound(_) | ty::Infer(ty::TyVar(_)) | ty::Infer(ty::FreshTy(_)) | ty::Infer(ty::FreshIntTy(_)) @@ -3248,7 +3248,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // assemble_candidates_for_unsizing should ensure there are no late bound // regions here. See the comment there for more details. let source = self.infcx - .shallow_resolve(obligation.self_ty().no_late_bound_regions().unwrap()); + .shallow_resolve(obligation.self_ty().no_bound_vars().unwrap()); let target = obligation .predicate .skip_binder() diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index d4b47db608163..29d36b5d3f6c4 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -2245,7 +2245,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { sty_debug_print!( self, Adt, Array, Slice, RawPtr, Ref, FnDef, FnPtr, - Generator, GeneratorWitness, Dynamic, Closure, Tuple, + Generator, GeneratorWitness, Dynamic, Closure, Tuple, Bound, Param, Infer, UnnormalizedProjection, Projection, Opaque, Foreign); println!("Substs interner: #{}", self.interners.substs.borrow().len()); diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index ed6e372fe7637..367f2d19b7313 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -217,7 +217,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::Infer(ty::TyVar(_)) => "inferred type".into(), ty::Infer(ty::IntVar(_)) => "integral variable".into(), ty::Infer(ty::FloatVar(_)) => "floating-point variable".into(), - ty::Infer(ty::BoundTy(_)) | + ty::Bound(_) | ty::Infer(ty::FreshTy(_)) => "fresh type".into(), ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(), ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(), diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index e6aaf8b1bb206..380f95993f8fb 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -122,7 +122,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::Foreign(def_id) => { Some(ForeignSimplifiedType(def_id)) } - ty::Infer(_) | ty::Error => None, + ty::Bound(..) | ty::Infer(_) | ty::Error => None, } } diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index a7b21688fbeb3..0764f363250dd 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -115,15 +115,17 @@ impl FlagComputation { self.add_substs(&substs.substs); } + &ty::Bound(bound_ty) => { + self.add_binder(bound_ty.index); + } + &ty::Infer(infer) => { self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); // it might, right? self.add_flags(TypeFlags::HAS_TY_INFER); match infer { ty::FreshTy(_) | ty::FreshIntTy(_) | - ty::FreshFloatTy(_) | - ty::BoundTy(_) => { - self.add_flags(TypeFlags::HAS_CANONICAL_VARS); + ty::FreshFloatTy(_) => { } ty::TyVar(_) | @@ -141,7 +143,7 @@ impl FlagComputation { &ty::Projection(ref data) => { // currently we can't normalize projections that // include bound regions, so track those separately. - if !data.has_escaping_regions() { + if !data.has_escaping_bound_vars() { self.add_flags(TypeFlags::HAS_NORMALIZABLE_PROJECTION); } self.add_flags(TypeFlags::HAS_PROJECTION); diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 80dfd263af9af..8c822adf7b023 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -67,18 +67,18 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { /// bound by `binder` or bound by some binder outside of `binder`. /// If `binder` is `ty::INNERMOST`, this indicates whether /// there are any late-bound regions that appear free. - fn has_regions_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool { - self.visit_with(&mut HasEscapingRegionsVisitor { outer_index: binder }) + fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool { + self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }) } /// True if this `self` has any regions that escape `binder` (and /// hence are not bound by it). - fn has_regions_bound_above(&self, binder: ty::DebruijnIndex) -> bool { - self.has_regions_bound_at_or_above(binder.shifted_in(1)) + fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool { + self.has_vars_bound_at_or_above(binder.shifted_in(1)) } - fn has_escaping_regions(&self) -> bool { - self.has_regions_bound_at_or_above(ty::INNERMOST) + fn has_escaping_bound_vars(&self) -> bool { + self.has_vars_bound_at_or_above(ty::INNERMOST) } fn has_type_flags(&self, flags: TypeFlags) -> bool { @@ -416,11 +416,10 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFolder<'a, 'gcx, 'tcx> { } /////////////////////////////////////////////////////////////////////////// -// Late-bound region replacer +// Bound vars replacer -// Replaces the escaping regions in a type. - -struct RegionReplacer<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { +/// Replaces the escaping bound vars (late bound regions or bound types) in a type. +struct BoundVarReplacer<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, /// As with `RegionFolder`, represents the index of a binder *just outside* @@ -428,7 +427,82 @@ struct RegionReplacer<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { current_index: ty::DebruijnIndex, fld_r: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a), - map: BTreeMap> + fld_t: &'a mut (dyn FnMut(ty::BoundTy) -> ty::Ty<'tcx> + 'a), +} + +impl<'a, 'gcx, 'tcx> BoundVarReplacer<'a, 'gcx, 'tcx> { + fn new( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + fld_r: &'a mut F, + fld_t: &'a mut G + ) -> Self + where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, + G: FnMut(ty::BoundTy) -> ty::Ty<'tcx> + { + BoundVarReplacer { + tcx, + current_index: ty::INNERMOST, + fld_r, + fld_t, + } + } +} + +impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for BoundVarReplacer<'a, 'gcx, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx } + + fn fold_binder>(&mut self, t: &ty::Binder) -> ty::Binder { + self.current_index.shift_in(1); + let t = t.super_fold_with(self); + self.current_index.shift_out(1); + t + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + match t.sty { + ty::Bound(bound_ty) => { + if bound_ty.index == self.current_index { + let fld_t = &mut self.fld_t; + let ty = fld_t(bound_ty); + ty::fold::shift_vars( + self.tcx, + &ty, + self.current_index.as_u32() + ) + } else { + t + } + } + _ => { + if !t.has_vars_bound_at_or_above(self.current_index) { + // Nothing more to substitute. + t + } else { + t.super_fold_with(self) + } + } + } + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + match *r { + ty::ReLateBound(debruijn, br) if debruijn == self.current_index => { + let fld_r = &mut self.fld_r; + let region = fld_r(br); + if let ty::ReLateBound(debruijn1, br) = *region { + // If the callback returns a late-bound region, + // that region should always use the INNERMOST + // debruijn index. Then we adjust it to the + // correct depth. + assert_eq!(debruijn1, ty::INNERMOST); + self.tcx.mk_region(ty::ReLateBound(debruijn, br)) + } else { + region + } + } + _ => r + } + } } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { @@ -440,16 +514,65 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// same `BoundRegion` will reuse the previous result. A map is /// returned at the end with each bound region and the free region /// that replaced it. - pub fn replace_late_bound_regions(self, + /// + /// This method only replaces late bound regions and the result may still + /// contain escaping bound types. + pub fn replace_late_bound_regions( + self, value: &Binder, - mut f: F) - -> (T, BTreeMap>) - where F : FnMut(ty::BoundRegion) -> ty::Region<'tcx>, - T : TypeFoldable<'tcx>, + mut fld_r: F + ) -> (T, BTreeMap>) + where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, + T: TypeFoldable<'tcx> { - let mut replacer = RegionReplacer::new(self, &mut f); + let mut map = BTreeMap::new(); + let mut real_fldr = |br| { + *map.entry(br).or_insert_with(|| fld_r(br)) + }; + + // identity for bound types + let mut fld_t = |bound_ty| self.mk_ty(ty::Bound(bound_ty)); + + let mut replacer = BoundVarReplacer::new(self, &mut real_fldr, &mut fld_t); let result = value.skip_binder().fold_with(&mut replacer); - (result, replacer.map) + (result, map) + } + + /// Replace all escaping bound vars. The `fld_r` closure replaces escaping + /// bound regions while the `fld_t` closure replaces escaping bound types. + pub fn replace_escaping_bound_vars( + self, + value: &T, + mut fld_r: F, + mut fld_t: G + ) -> T + where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, + G: FnMut(ty::BoundTy) -> ty::Ty<'tcx>, + T: TypeFoldable<'tcx> + { + if !value.has_escaping_bound_vars() { + value.clone() + } else { + let mut replacer = BoundVarReplacer::new(self, &mut fld_r, &mut fld_t); + let result = value.fold_with(&mut replacer); + result + } + } + + /// Replace all types or regions bound by the given `Binder`. The `fld_r` + /// closure replaces bound regions while the `fld_t` closure replaces bound + /// types. + pub fn replace_bound_vars( + self, + value: &Binder, + fld_r: F, + fld_t: G + ) -> T + where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, + G: FnMut(ty::BoundTy) -> ty::Ty<'tcx>, + T: TypeFoldable<'tcx> + { + self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t) } /// Replace any late-bound regions bound in `value` with @@ -549,21 +672,33 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> { - fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, fld_r: &'a mut F) - -> RegionReplacer<'a, 'gcx, 'tcx> - where F : FnMut(ty::BoundRegion) -> ty::Region<'tcx> - { - RegionReplacer { +/////////////////////////////////////////////////////////////////////////// +// Shifter +// +// Shifts the De Bruijn indices on all escaping bound vars by a +// fixed amount. Useful in substitution or when otherwise introducing +// a binding level that is not intended to capture the existing bound +// vars. See comment on `shift_vars_through_binders` method in +// `subst.rs` for more details. + +struct Shifter<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { + tcx: TyCtxt<'a, 'gcx, 'tcx>, + + current_index: ty::DebruijnIndex, + amount: u32, +} + +impl Shifter<'a, 'gcx, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, amount: u32) -> Self { + Shifter { tcx, current_index: ty::INNERMOST, - fld_r, - map: BTreeMap::default() + amount, } } } -impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionReplacer<'a, 'gcx, 'tcx> { +impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Shifter<'a, 'gcx, 'tcx> { fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx } fn fold_binder>(&mut self, t: &ty::Binder) -> ty::Binder { @@ -573,64 +708,48 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionReplacer<'a, 'gcx, 'tcx> { t } - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.has_regions_bound_at_or_above(self.current_index) { - return t; - } - - t.super_fold_with(self) - } - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { - ty::ReLateBound(debruijn, br) if debruijn == self.current_index => { - let fld_r = &mut self.fld_r; - let region = *self.map.entry(br).or_insert_with(|| fld_r(br)); - if let ty::ReLateBound(debruijn1, br) = *region { - // If the callback returns a late-bound region, - // that region should always use the INNERMOST - // debruijn index. Then we adjust it to the - // correct depth. - assert_eq!(debruijn1, ty::INNERMOST); - self.tcx.mk_region(ty::ReLateBound(debruijn, br)) + ty::ReLateBound(debruijn, br) => { + if self.amount == 0 || debruijn < self.current_index { + r } else { - region + let shifted = ty::ReLateBound(debruijn.shifted_in(self.amount), br); + self.tcx.mk_region(shifted) } } _ => r } } -} -/////////////////////////////////////////////////////////////////////////// -// Region shifter -// -// Shifts the De Bruijn indices on all escaping bound regions by a -// fixed amount. Useful in substitution or when otherwise introducing -// a binding level that is not intended to capture the existing bound -// regions. See comment on `shift_regions_through_binders` method in -// `subst.rs` for more details. + fn fold_ty(&mut self, ty: ty::Ty<'tcx>) -> ty::Ty<'tcx> { + match ty.sty { + ty::Bound(bound_ty) => { + if self.amount == 0 || bound_ty.index < self.current_index { + ty + } else { + let shifted = ty::BoundTy { + index: bound_ty.index.shifted_in(self.amount), + var: bound_ty.var, + kind: bound_ty.kind, + }; + self.tcx.mk_ty(ty::Bound(shifted)) + } + } -pub fn shift_region(region: ty::RegionKind, amount: u32) -> ty::RegionKind { - match region { - ty::ReLateBound(debruijn, br) => { - ty::ReLateBound(debruijn.shifted_in(amount), br) - } - _ => { - region + _ => ty.super_fold_with(self), } } } -pub fn shift_region_ref<'a, 'gcx, 'tcx>( +pub fn shift_region<'a, 'gcx, 'tcx>( tcx: TyCtxt<'a, 'gcx, 'tcx>, region: ty::Region<'tcx>, - amount: u32) - -> ty::Region<'tcx> -{ + amount: u32 +) -> ty::Region<'tcx> { match region { - &ty::ReLateBound(debruijn, br) if amount > 0 => { - tcx.mk_region(ty::ReLateBound(debruijn.shifted_in(amount), br)) + ty::ReLateBound(debruijn, br) if amount > 0 => { + tcx.mk_region(ty::ReLateBound(debruijn.shifted_in(amount), *br)) } _ => { region @@ -638,20 +757,19 @@ pub fn shift_region_ref<'a, 'gcx, 'tcx>( } } -pub fn shift_regions<'a, 'gcx, 'tcx, T>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - amount: u32, - value: &T) -> T - where T: TypeFoldable<'tcx> -{ - debug!("shift_regions(value={:?}, amount={})", +pub fn shift_vars<'a, 'gcx, 'tcx, T>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + value: &T, + amount: u32 +) -> T where T: TypeFoldable<'tcx> { + debug!("shift_vars(value={:?}, amount={})", value, amount); - value.fold_with(&mut RegionFolder::new(tcx, &mut false, &mut |region, _current_depth| { - shift_region_ref(tcx, region, amount) - })) + value.fold_with(&mut Shifter::new(tcx, amount)) } -/// An "escaping region" is a bound region whose binder is not part of `t`. +/// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a +/// bound region or a bound type. /// /// So, for example, consider a type like the following, which has two binders: /// @@ -663,24 +781,24 @@ pub fn shift_regions<'a, 'gcx, 'tcx, T>(tcx: TyCtxt<'a, 'gcx, 'tcx>, /// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner /// fn type*, that type has an escaping region: `'a`. /// -/// Note that what I'm calling an "escaping region" is often just called a "free region". However, -/// we already use the term "free region". It refers to the regions that we use to represent bound -/// regions on a fn definition while we are typechecking its body. +/// Note that what I'm calling an "escaping var" is often just called a "free var". However, +/// we already use the term "free var". It refers to the regions or types that we use to represent +/// bound regions or type params on a fn definition while we are typechecking its body. /// /// To clarify, conceptually there is no particular difference between -/// an "escaping" region and a "free" region. However, there is a big +/// an "escaping" var and a "free" var. However, there is a big /// difference in practice. Basically, when "entering" a binding /// level, one is generally required to do some sort of processing to -/// a bound region, such as replacing it with a fresh/placeholder -/// region, or making an entry in the environment to represent the -/// scope to which it is attached, etc. An escaping region represents -/// a bound region for which this processing has not yet been done. -struct HasEscapingRegionsVisitor { +/// a bound var, such as replacing it with a fresh/placeholder +/// var, or making an entry in the environment to represent the +/// scope to which it is attached, etc. An escaping var represents +/// a bound var for which this processing has not yet been done. +struct HasEscapingVarsVisitor { /// Anything bound by `outer_index` or "above" is escaping outer_index: ty::DebruijnIndex, } -impl<'tcx> TypeVisitor<'tcx> for HasEscapingRegionsVisitor { +impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { fn visit_binder>(&mut self, t: &Binder) -> bool { self.outer_index.shift_in(1); let result = t.super_visit_with(self); @@ -693,7 +811,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingRegionsVisitor { // `outer_index`, that means that `t` contains some content // bound at `outer_index` or above (because // `outer_exclusive_binder` is always 1 higher than the - // content in `t`). Therefore, `t` has some escaping regions. + // content in `t`). Therefore, `t` has some escaping vars. t.outer_exclusive_binder > self.outer_index } diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 041565c8b5a07..2fc8ef548fa04 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -213,7 +213,7 @@ impl<'tcx> fmt::Display for Instance<'tcx> { impl<'a, 'b, 'tcx> Instance<'tcx> { pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>) -> Instance<'tcx> { - assert!(!substs.has_escaping_regions(), + assert!(!substs.has_escaping_bound_vars(), "substs of instance {:?} not normalized for codegen: {:?}", def_id, substs); Instance { def: InstanceDef::Item(def_id), substs: substs } diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 7153c729d1542..d44ba03084159 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -519,6 +519,7 @@ pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option { ty::Param(_) | ty::Opaque(..) | ty::Infer(_) | + ty::Bound(..) | ty::Error | ty::GeneratorWitness(..) | ty::Never | diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 05d4aeb6ddec4..5500572161735 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1124,9 +1124,14 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } tcx.layout_raw(param_env.and(normalized))? } - ty::UnnormalizedProjection(..) | ty::GeneratorWitness(..) | ty::Infer(_) => { + + ty::Bound(..) | + ty::UnnormalizedProjection(..) | + ty::GeneratorWitness(..) | + ty::Infer(_) => { bug!("LayoutDetails::compute: unexpected type `{}`", ty) } + ty::Param(_) | ty::Error => { return Err(LayoutError::Unknown(ty)); } @@ -1703,7 +1708,7 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> } } - ty::Projection(_) | ty::UnnormalizedProjection(..) | + ty::Projection(_) | ty::UnnormalizedProjection(..) | ty::Bound(..) | ty::Opaque(..) | ty::Param(_) | ty::Infer(_) | ty::Error => { bug!("TyLayout::field_type: unexpected type `{}`", this.ty) } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f8fc2cc83034f..e15a8170c98ed 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -63,7 +63,7 @@ use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, use hir; -pub use self::sty::{Binder, BoundTy, BoundTyIndex, DebruijnIndex, INNERMOST}; +pub use self::sty::{Binder, BoundTy, BoundTyKind, BoundVar, DebruijnIndex, INNERMOST}; pub use self::sty::{FnSig, GenSig, CanonicalPolyFnSig, PolyFnSig, PolyGenSig}; pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate}; pub use self::sty::{ClosureSubsts, GeneratorSubsts, UpvarSubsts, TypeAndMut}; @@ -463,13 +463,9 @@ bitflags! { // Currently we can't normalize projections w/ bound regions. const HAS_NORMALIZABLE_PROJECTION = 1 << 12; - // Set if this includes a "canonical" type or region var -- - // ought to be true only for the results of canonicalization. - const HAS_CANONICAL_VARS = 1 << 13; - /// Does this have any `ReLateBound` regions? Used to check /// if a global bound is safe to evaluate. - const HAS_RE_LATE_BOUND = 1 << 14; + const HAS_RE_LATE_BOUND = 1 << 13; const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits | TypeFlags::HAS_SELF.bits | @@ -490,7 +486,6 @@ bitflags! { TypeFlags::HAS_TY_CLOSURE.bits | TypeFlags::HAS_FREE_LOCAL_NAMES.bits | TypeFlags::KEEP_IN_LOCAL_TCX.bits | - TypeFlags::HAS_CANONICAL_VARS.bits | TypeFlags::HAS_RE_LATE_BOUND.bits; } } @@ -2369,6 +2364,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } + Bound(..) | Infer(..) => { bug!("unexpected type `{:?}` in sized_constraint_for_ty", ty) diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index b49664b624733..449730c9d0601 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -106,7 +106,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // we simply fallback to the most restrictive rule, which // requires that `Pi: 'a` for all `i`. ty::Projection(ref data) => { - if !data.has_escaping_regions() { + if !data.has_escaping_bound_vars() { // best case: no escaping regions, so push the // projection and skip the subtree (thus generating no // constraints for Pi). This defers the choice between @@ -156,6 +156,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::FnDef(..) | // OutlivesFunction (*) ty::FnPtr(_) | // OutlivesFunction (*) ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*) + ty::Bound(..) | ty::Error => { // (*) Bare functions and traits are both binders. In the // RFC, this means we would add the bound regions to the diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index ba5b714a0e7d9..dc1c01d94d7d3 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -735,9 +735,19 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::UnnormalizedProjection(data.fold_with(folder)) } ty::Opaque(did, substs) => ty::Opaque(did, substs.fold_with(folder)), - ty::Bool | ty::Char | ty::Str | ty::Int(_) | - ty::Uint(_) | ty::Float(_) | ty::Error | ty::Infer(_) | - ty::Param(..) | ty::Never | ty::Foreign(..) => return self + + ty::Bool | + ty::Char | + ty::Str | + ty::Int(_) | + ty::Uint(_) | + ty::Float(_) | + ty::Error | + ty::Infer(_) | + ty::Param(..) | + ty::Bound(..) | + ty::Never | + ty::Foreign(..) => return self }; if self.sty == sty { @@ -772,9 +782,19 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { data.visit_with(visitor) } ty::Opaque(_, ref substs) => substs.visit_with(visitor), - ty::Bool | ty::Char | ty::Str | ty::Int(_) | - ty::Uint(_) | ty::Float(_) | ty::Error | ty::Infer(_) | - ty::Param(..) | ty::Never | ty::Foreign(..) => false, + + ty::Bool | + ty::Char | + ty::Str | + ty::Int(_) | + ty::Uint(_) | + ty::Float(_) | + ty::Error | + ty::Infer(_) | + ty::Bound(..) | + ty::Param(..) | + ty::Never | + ty::Foreign(..) => false, } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 62e38ad9bfa66..6929cb988d051 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -77,6 +77,17 @@ impl BoundRegion { _ => false, } } + + /// When canonicalizing, we replace unbound inference variables and free + /// regions with anonymous late bound regions. This method asserts that + /// we have an anonymous late bound region, which hence may refer to + /// a canonical variable. + pub fn assert_bound_var(&self) -> BoundVar { + match *self { + BoundRegion::BrAnon(var) => BoundVar::from_u32(var), + _ => bug!("bound region is not anonymous"), + } + } } /// N.B., If you change this, you'll probably want to change the corresponding @@ -188,6 +199,9 @@ pub enum TyKind<'tcx> { /// A type parameter; for example, `T` in `fn f(x: T) {} Param(ParamTy), + /// Bound type variable, used only when preparing a trait query. + Bound(BoundTy), + /// A type variable used during type checking. Infer(InferTy), @@ -727,8 +741,8 @@ impl<'a, 'gcx, 'tcx> ExistentialTraitRef<'tcx> { /// or some placeholder type. pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, self_ty: Ty<'tcx>) -> ty::TraitRef<'tcx> { - // otherwise the escaping regions would be captured by the binder - // debug_assert!(!self_ty.has_escaping_regions()); + // otherwise the escaping vars would be captured by the binder + // debug_assert!(!self_ty.has_escaping_bound_vars()); ty::TraitRef { def_id: self.def_id, @@ -755,11 +769,11 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> { } } -/// Binder is a binder for higher-ranked lifetimes. It is part of the +/// Binder is a binder for higher-ranked lifetimes or types. It is part of the /// compiler's representation for things like `for<'a> Fn(&'a isize)` /// (which would be represented by the type `PolyTraitRef == /// Binder`). Note that when we instantiate, -/// erase, or otherwise "discharge" these bound regions, we change the +/// erase, or otherwise "discharge" these bound vars, we change the /// type from `Binder` to just `T` (see /// e.g. `liberate_late_bound_regions`). #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] @@ -767,29 +781,28 @@ pub struct Binder(T); impl Binder { /// Wraps `value` in a binder, asserting that `value` does not - /// contain any bound regions that would be bound by the + /// contain any bound vars that would be bound by the /// binder. This is commonly used to 'inject' a value T into a /// different binding level. pub fn dummy<'tcx>(value: T) -> Binder where T: TypeFoldable<'tcx> { - debug_assert!(!value.has_escaping_regions()); + debug_assert!(!value.has_escaping_bound_vars()); Binder(value) } - /// Wraps `value` in a binder, binding late-bound regions (if any). - pub fn bind<'tcx>(value: T) -> Binder - { + /// Wraps `value` in a binder, binding higher-ranked vars (if any). + pub fn bind<'tcx>(value: T) -> Binder { Binder(value) } /// Skips the binder and returns the "bound" value. This is a /// risky thing to do because it's easy to get confused about /// debruijn indices and the like. It is usually better to - /// discharge the binder using `no_late_bound_regions` or + /// discharge the binder using `no_bound_vars` or /// `replace_late_bound_regions` or something like /// that. `skip_binder` is only valid when you are either - /// extracting data that has nothing to do with bound regions, you + /// extracting data that has nothing to do with bound vars, you /// are doing some sort of test that does not involve bound /// regions, or you are being very careful about your depth /// accounting. @@ -798,7 +811,7 @@ impl Binder { /// /// - extracting the def-id from a PolyTraitRef; /// - comparing the self type of a PolyTraitRef to see if it is equal to - /// a type parameter `X`, since the type `X` does not reference any regions + /// a type parameter `X`, since the type `X` does not reference any regions pub fn skip_binder(&self) -> &T { &self.0 } @@ -820,19 +833,19 @@ impl Binder { } /// Unwraps and returns the value within, but only if it contains - /// no bound regions at all. (In other words, if this binder -- + /// no bound vars at all. (In other words, if this binder -- /// and indeed any enclosing binder -- doesn't bind anything at /// all.) Otherwise, returns `None`. /// /// (One could imagine having a method that just unwraps a single - /// binder, but permits late-bound regions bound by enclosing + /// binder, but permits late-bound vars bound by enclosing /// binders, but that would require adjusting the debruijn /// indices, and given the shallow binding structure we often use, /// would not be that useful.) - pub fn no_late_bound_regions<'tcx>(self) -> Option - where T : TypeFoldable<'tcx> + pub fn no_bound_vars<'tcx>(self) -> Option + where T: TypeFoldable<'tcx> { - if self.skip_binder().has_escaping_regions() { + if self.skip_binder().has_escaping_bound_vars() { None } else { Some(self.skip_binder().clone()) @@ -1166,9 +1179,6 @@ pub enum RegionKind { /// `ClosureRegionRequirements` that are produced by MIR borrowck. /// See `ClosureRegionRequirements` for more details. ReClosureBound(RegionVid), - - /// Canonicalized region, used only when preparing a trait query. - ReCanonical(BoundTyIndex), } impl<'tcx> serialize::UseSpecializedDecodable for Region<'tcx> {} @@ -1219,22 +1229,37 @@ pub enum InferTy { FreshTy(u32), FreshIntTy(u32), FreshFloatTy(u32), - - /// Bound type variable, used only when preparing a trait query. - BoundTy(BoundTy), } newtype_index! { - pub struct BoundTyIndex { .. } + pub struct BoundVar { .. } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct BoundTy { - pub level: DebruijnIndex, - pub var: BoundTyIndex, + pub index: DebruijnIndex, + pub var: BoundVar, + pub kind: BoundTyKind, } -impl_stable_hash_for!(struct BoundTy { level, var }); +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] +pub enum BoundTyKind { + Anon, + Param(InternedString), +} + +impl_stable_hash_for!(struct BoundTy { index, var, kind }); +impl_stable_hash_for!(enum self::BoundTyKind { Anon, Param(a) }); + +impl BoundTy { + pub fn new(index: DebruijnIndex, var: BoundVar) -> Self { + BoundTy { + index, + var, + kind: BoundTyKind::Anon, + } + } +} /// A `ProjectionPredicate` for an `ExistentialTraitRef`. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] @@ -1264,7 +1289,7 @@ impl<'a, 'tcx, 'gcx> ExistentialProjection<'tcx> { -> ty::ProjectionPredicate<'tcx> { // otherwise the escaping regions would be captured by the binders - debug_assert!(!self_ty.has_escaping_regions()); + debug_assert!(!self_ty.has_escaping_bound_vars()); ty::ProjectionPredicate { projection_ty: ty::ProjectionTy { @@ -1363,7 +1388,6 @@ impl RegionKind { RegionKind::ReEmpty => false, RegionKind::ReErased => false, RegionKind::ReClosureBound(..) => false, - RegionKind::ReCanonical(..) => false, } } @@ -1450,10 +1474,6 @@ impl RegionKind { } ty::ReErased => { } - ty::ReCanonical(..) => { - flags = flags | TypeFlags::HAS_FREE_REGIONS; - flags = flags | TypeFlags::HAS_CANONICAL_VARS; - } ty::ReClosureBound(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; } @@ -1865,6 +1885,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { Tuple(..) | Foreign(..) | Param(_) | + Bound(..) | Infer(_) | Error => { vec![] @@ -1930,7 +1951,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { ty::Infer(ty::TyVar(_)) => false, - ty::Infer(ty::BoundTy(_)) | + ty::Bound(_) | ty::Infer(ty::FreshTy(_)) | ty::Infer(ty::FreshIntTy(_)) | ty::Infer(ty::FreshFloatTy(_)) => diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 02b5d36ecce6e..c1aed36c92ddf 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -12,7 +12,7 @@ use hir::def_id::DefId; use infer::canonical::Canonical; -use ty::{self, BoundTyIndex, Lift, List, Ty, TyCtxt}; +use ty::{self, BoundVar, Lift, List, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use serialize::{self, Encodable, Encoder, Decodable, Decoder}; @@ -355,7 +355,7 @@ impl<'tcx, T:TypeFoldable<'tcx>> Subst<'tcx> for T { span, root_ty: None, ty_stack_depth: 0, - region_binders_passed: 0 }; + binders_passed: 0 }; (*self).fold_with(&mut folder) } } @@ -377,16 +377,16 @@ struct SubstFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { ty_stack_depth: usize, // Number of region binders we have passed through while doing the substitution - region_binders_passed: u32, + binders_passed: u32, } impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> { fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx } fn fold_binder>(&mut self, t: &ty::Binder) -> ty::Binder { - self.region_binders_passed += 1; + self.binders_passed += 1; let t = t.super_fold_with(self); - self.region_binders_passed -= 1; + self.binders_passed -= 1; t } @@ -471,12 +471,12 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { } }; - self.shift_regions_through_binders(ty) + self.shift_vars_through_binders(ty) } /// It is sometimes necessary to adjust the debruijn indices during substitution. This occurs - /// when we are substituting a type with escaping regions into a context where we have passed - /// through region binders. That's quite a mouthful. Let's see an example: + /// when we are substituting a type with escaping bound vars into a context where we have + /// passed through binders. That's quite a mouthful. Let's see an example: /// /// ``` /// type Func = fn(A); @@ -516,25 +516,25 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { /// As indicated in the diagram, here the same type `&'a int` is substituted once, but in the /// first case we do not increase the Debruijn index and in the second case we do. The reason /// is that only in the second case have we passed through a fn binder. - fn shift_regions_through_binders(&self, ty: Ty<'tcx>) -> Ty<'tcx> { - debug!("shift_regions(ty={:?}, region_binders_passed={:?}, has_escaping_regions={:?})", - ty, self.region_binders_passed, ty.has_escaping_regions()); + fn shift_vars_through_binders(&self, ty: Ty<'tcx>) -> Ty<'tcx> { + debug!("shift_vars(ty={:?}, binders_passed={:?}, has_escaping_bound_vars={:?})", + ty, self.binders_passed, ty.has_escaping_bound_vars()); - if self.region_binders_passed == 0 || !ty.has_escaping_regions() { + if self.binders_passed == 0 || !ty.has_escaping_bound_vars() { return ty; } - let result = ty::fold::shift_regions(self.tcx(), self.region_binders_passed, &ty); - debug!("shift_regions: shifted result = {:?}", result); + let result = ty::fold::shift_vars(self.tcx(), &ty, self.binders_passed); + debug!("shift_vars: shifted result = {:?}", result); result } fn shift_region_through_binders(&self, region: ty::Region<'tcx>) -> ty::Region<'tcx> { - if self.region_binders_passed == 0 || !region.has_escaping_regions() { + if self.binders_passed == 0 || !region.has_escaping_bound_vars() { return region; } - self.tcx().mk_region(ty::fold::shift_region(*region, self.region_binders_passed)) + ty::fold::shift_region(self.tcx, region, self.binders_passed) } } @@ -553,15 +553,23 @@ impl CanonicalUserSubsts<'tcx> { return false; } - self.value.substs.iter().zip(BoundTyIndex::new(0)..).all(|(kind, cvar)| { + self.value.substs.iter().zip(BoundVar::new(0)..).all(|(kind, cvar)| { match kind.unpack() { UnpackedKind::Type(ty) => match ty.sty { - ty::Infer(ty::BoundTy(ref b)) => cvar == b.var, + ty::Bound(b) => { + // We only allow a `ty::INNERMOST` index in substitutions. + assert_eq!(b.index, ty::INNERMOST); + cvar == b.var + } _ => false, }, UnpackedKind::Lifetime(r) => match r { - ty::ReCanonical(cvar1) => cvar == *cvar1, + ty::ReLateBound(index, br) => { + // We only allow a `ty::INNERMOST` index in substitutions. + assert_eq!(*index, ty::INNERMOST); + cvar == br.assert_bound_var() + } _ => false, }, } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 00a1bfaacd781..1b1bbfd4deb8b 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -363,7 +363,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { erased_self_ty, predicates); - assert!(!erased_self_ty.has_escaping_regions()); + assert!(!erased_self_ty.has_escaping_bound_vars()); traits::elaborate_predicates(self, predicates) .filter_map(|predicate| { @@ -389,7 +389,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // construct such an object, but this seems // correct even if that code changes). let ty::OutlivesPredicate(ref t, ref r) = predicate.skip_binder(); - if t == &erased_self_ty && !r.has_escaping_regions() { + if t == &erased_self_ty && !r.has_escaping_bound_vars() { Some(*r) } else { None @@ -951,7 +951,7 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Can refer to a type which may drop. // FIXME(eddyb) check this against a ParamEnv. - ty::Dynamic(..) | ty::Projection(..) | ty::Param(_) | + ty::Dynamic(..) | ty::Projection(..) | ty::Param(_) | ty::Bound(..) | ty::Opaque(..) | ty::Infer(_) | ty::Error => true, ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index 47fbfba87748b..284c595ee2d96 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -82,7 +82,7 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { match parent_ty.sty { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Infer(_) | ty::Param(_) | ty::Never | ty::Error | - ty::Foreign(..) => { + ty::Bound(..) | ty::Foreign(..) => { } ty::Array(ty, len) => { push_const(stack, len); diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 27747970f76b2..1336eac63f880 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -158,7 +158,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { let infcx = &mut self.infcx; let param_env = self.param_env; self.out.iter() - .inspect(|pred| assert!(!pred.has_escaping_regions())) + .inspect(|pred| assert!(!pred.has_escaping_bound_vars())) .flat_map(|pred| { let mut selcx = traits::SelectionContext::new(infcx); let pred = traits::normalize(&mut selcx, param_env, cause.clone(), pred); @@ -190,7 +190,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { self.out.extend( trait_ref.substs.types() - .filter(|ty| !ty.has_escaping_regions()) + .filter(|ty| !ty.has_escaping_bound_vars()) .map(|ty| traits::Obligation::new(cause.clone(), param_env, ty::Predicate::WellFormed(ty)))); @@ -205,7 +205,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { let trait_ref = data.trait_ref(self.infcx.tcx); self.compute_trait_ref(&trait_ref, Elaborate::None); - if !data.has_escaping_regions() { + if !data.has_escaping_bound_vars() { let predicate = trait_ref.to_predicate(); let cause = self.cause(traits::ProjectionWf(data)); self.out.push(traits::Obligation::new(cause, self.param_env, predicate)); @@ -229,7 +229,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { } fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) { - if !subty.has_escaping_regions() { + if !subty.has_escaping_bound_vars() { let cause = self.cause(cause); let trait_ref = ty::TraitRef { def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem), @@ -258,6 +258,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { ty::GeneratorWitness(..) | ty::Never | ty::Param(_) | + ty::Bound(..) | ty::Foreign(..) => { // WfScalar, WfParameter, etc } @@ -299,7 +300,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { ty::Ref(r, rty, _) => { // WfReference - if !r.has_escaping_regions() && !rty.has_escaping_regions() { + if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() { let cause = self.cause(traits::ReferenceOutlivesReferent(ty)); self.out.push( traits::Obligation::new( @@ -450,7 +451,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { .map(|pred| traits::Obligation::new(cause.clone(), self.param_env, pred)) - .filter(|pred| !pred.has_escaping_regions()) + .filter(|pred| !pred.has_escaping_bound_vars()) .collect() } @@ -489,7 +490,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { // Note: in fact we only permit builtin traits, not `Bar<'d>`, I // am looking forward to the future here. - if !data.has_escaping_regions() { + if !data.has_escaping_bound_vars() { let implicit_bounds = object_region_bounds(self.infcx.tcx, data); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 709b844526529..92513621be498 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -16,7 +16,7 @@ use ty::subst::{self, Subst}; use ty::{BrAnon, BrEnv, BrFresh, BrNamed}; use ty::{Bool, Char, Adt}; use ty::{Error, Str, Array, Slice, Float, FnDef, FnPtr}; -use ty::{Param, RawPtr, Ref, Never, Tuple}; +use ty::{Param, Bound, RawPtr, Ref, Never, Tuple}; use ty::{Closure, Generator, GeneratorWitness, Foreign, Projection, Opaque}; use ty::{UnnormalizedProjection, Dynamic, Int, Uint, Infer}; use ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind}; @@ -798,9 +798,6 @@ define_print! { ty::ReEarlyBound(ref data) => { write!(f, "{}", data.name) } - ty::ReCanonical(_) => { - write!(f, "'_") - } ty::ReLateBound(_, br) | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { @@ -868,10 +865,6 @@ define_print! { write!(f, "{:?}", vid) } - ty::ReCanonical(c) => { - write!(f, "'?{}", c.index()) - } - ty::RePlaceholder(placeholder) => { write!(f, "RePlaceholder({:?})", placeholder) } @@ -984,7 +977,6 @@ define_print! { ty::TyVar(_) => write!(f, "_"), ty::IntVar(_) => write!(f, "{}", "{integer}"), ty::FloatVar(_) => write!(f, "{}", "{float}"), - ty::BoundTy(_) => write!(f, "_"), ty::FreshTy(v) => write!(f, "FreshTy({})", v), ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v), ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v) @@ -996,7 +988,6 @@ define_print! { ty::TyVar(ref v) => write!(f, "{:?}", v), ty::IntVar(ref v) => write!(f, "{:?}", v), ty::FloatVar(ref v) => write!(f, "{:?}", v), - ty::BoundTy(v) => write!(f, "?{:?}", v.var.index()), ty::FreshTy(v) => write!(f, "FreshTy({:?})", v), ty::FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v), ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v) @@ -1127,6 +1118,19 @@ define_print! { Infer(infer_ty) => write!(f, "{}", infer_ty), Error => write!(f, "[type error]"), Param(ref param_ty) => write!(f, "{}", param_ty), + Bound(bound_ty) => { + match bound_ty.kind { + ty::BoundTyKind::Anon => { + if bound_ty.index == ty::INNERMOST { + write!(f, "?{}", bound_ty.var.index()) + } else { + write!(f, "?{}_{}", bound_ty.index.index(), bound_ty.var.index()) + } + } + + ty::BoundTyKind::Param(p) => write!(f, "{}", p), + } + } Adt(def, substs) => cx.parameterized(f, substs, def.did, &[]), Dynamic(data, r) => { let r = r.print_to_string(cx); diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 1fc9ee07a1ae4..a802729e3fbdb 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -426,7 +426,6 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { // These cannot exist in borrowck RegionKind::ReVar(..) | - RegionKind::ReCanonical(..) | RegionKind::RePlaceholder(..) | RegionKind::ReClosureBound(..) | RegionKind::ReErased => span_bug!(borrow_span, diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 1f83c30a3876a..78a31ed668fca 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -363,7 +363,6 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { ty::ReStatic => self.item_ub, - ty::ReCanonical(_) | ty::ReEmpty | ty::ReClosureBound(..) | ty::ReLateBound(..) | diff --git a/src/librustc_codegen_llvm/back/archive.rs b/src/librustc_codegen_llvm/back/archive.rs index af9efc6d7c417..ce4cb1ea3a042 100644 --- a/src/librustc_codegen_llvm/back/archive.rs +++ b/src/librustc_codegen_llvm/back/archive.rs @@ -52,28 +52,6 @@ enum Addition { }, } -pub fn find_library(name: &str, search_paths: &[PathBuf], sess: &Session) - -> PathBuf { - // On Windows, static libraries sometimes show up as libfoo.a and other - // times show up as foo.lib - let oslibname = format!("{}{}{}", - sess.target.target.options.staticlib_prefix, - name, - sess.target.target.options.staticlib_suffix); - let unixlibname = format!("lib{}.a", name); - - for path in search_paths { - debug!("looking for {} inside {:?}", name, path); - let test = path.join(&oslibname); - if test.exists() { return test } - if oslibname != unixlibname { - let test = path.join(&unixlibname); - if test.exists() { return test } - } - } - sess.fatal(&format!("could not find native static library `{}`, \ - perhaps an -L flag is missing?", name)); -} fn is_relevant_child(c: &Child) -> bool { match c.name() { @@ -128,7 +106,7 @@ impl<'a> ArchiveBuilder<'a> { /// Adds all of the contents of a native library to this archive. This will /// search in the relevant locations for a library named `name`. pub fn add_native_library(&mut self, name: &str) { - let location = find_library(name, &self.config.lib_search_paths, + let location = ::rustc_codegen_utils::find_library(name, &self.config.lib_search_paths, self.config.sess); self.add_archive(&location, |_| false).unwrap_or_else(|e| { self.config.sess.fatal(&format!("failed to add native library {}: {}", diff --git a/src/librustc_codegen_llvm/back/link.rs b/src/librustc_codegen_llvm/back/link.rs index 86c6a5e65b0e9..dd95c3d986299 100644 --- a/src/librustc_codegen_llvm/back/link.rs +++ b/src/librustc_codegen_llvm/back/link.rs @@ -12,8 +12,6 @@ use back::wasm; use cc::windows_registry; use super::archive::{ArchiveBuilder, ArchiveConfig}; use super::bytecode::RLIB_BYTECODE_EXTENSION; -use super::linker::Linker; -use super::command::Command; use super::rpath::RPathConfig; use super::rpath; use metadata::METADATA_FILENAME; @@ -31,6 +29,8 @@ use rustc::hir::def_id::CrateNum; use tempfile::{Builder as TempFileBuilder, TempDir}; use rustc_target::spec::{PanicStrategy, RelroLevel, LinkerFlavor}; use rustc_data_structures::fx::FxHashSet; +use rustc_codegen_utils::linker::Linker; +use rustc_codegen_utils::command::Command; use context::get_reloc_model; use llvm; @@ -701,7 +701,8 @@ fn link_natively(sess: &Session, } { - let mut linker = codegen_results.linker_info.to_linker(cmd, &sess, flavor); + let target_cpu = ::llvm_util::target_cpu(sess); + let mut linker = codegen_results.linker_info.to_linker(cmd, &sess, flavor, target_cpu); link_args(&mut *linker, flavor, sess, crate_type, tmpdir, out_filename, codegen_results); cmd = linker.finalize(); diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs index 61856236a1491..8f940e0d22a83 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -9,7 +9,6 @@ // except according to those terms. use back::bytecode::{DecodedBytecode, RLIB_BYTECODE_EXTENSION}; -use back::symbol_export; use back::write::{ModuleConfig, with_llvm_pmb, CodegenContext}; use back::write::{self, DiagnosticHandlers, pre_lto_bitcode_filename}; use errors::{FatalError, Handler}; @@ -24,6 +23,7 @@ use rustc::middle::exported_symbols::SymbolExportLevel; use rustc::session::config::{self, Lto}; use rustc::util::common::time_ext; use rustc_data_structures::fx::FxHashMap; +use rustc_codegen_utils::symbol_export; use time_graph::Timeline; use {ModuleCodegen, ModuleLlvm, ModuleKind}; diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 81619c219757b..333a778e7765f 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -12,9 +12,6 @@ use attributes; use back::bytecode::{self, RLIB_BYTECODE_EXTENSION}; use back::lto::{self, ModuleBuffer, ThinBuffer, SerializedModule}; use back::link::{self, get_linker, remove}; -use back::command::Command; -use back::linker::LinkerInfo; -use back::symbol_export::ExportedSymbols; use base; use consts; use memmap; @@ -38,6 +35,9 @@ use rustc::util::common::{time_ext, time_depth, set_time_depth, print_time_passe use rustc_fs_util::{path2cstr, link_or_copy}; use rustc_data_structures::small_c_str::SmallCStr; use rustc_data_structures::svh::Svh; +use rustc_codegen_utils::command::Command; +use rustc_codegen_utils::linker::LinkerInfo; +use rustc_codegen_utils::symbol_export::ExportedSymbols; use errors::{self, Handler, Level, DiagnosticBuilder, FatalError, DiagnosticId}; use errors::emitter::{Emitter}; use syntax::attr; diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index a4c7a7123b964..b7147e8e5422c 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -54,7 +54,6 @@ use attributes; use builder::{Builder, MemFlags}; use callee; use common::{C_bool, C_bytes_in_context, C_i32, C_usize}; -use rustc_mir::monomorphize::collector::{self, MonoItemCollectionMode}; use rustc_mir::monomorphize::item::DefPathBasedNames; use common::{C_struct_in_context, C_array, val_ty}; use consts; @@ -64,20 +63,19 @@ use declare; use meth; use mir; use monomorphize::Instance; -use monomorphize::partitioning::{self, PartitioningStrategy, CodegenUnit, CodegenUnitExt}; +use monomorphize::partitioning::{CodegenUnit, CodegenUnitExt}; use rustc_codegen_utils::symbol_names_test; use time_graph; -use mono_item::{MonoItem, BaseMonoItemExt, MonoItemExt}; +use mono_item::{MonoItem, MonoItemExt}; use type_::Type; use type_of::LayoutLlvmExt; -use rustc::util::nodemap::{FxHashMap, DefIdSet}; +use rustc::util::nodemap::FxHashMap; use CrateInfo; use rustc_data_structures::small_c_str::SmallCStr; use rustc_data_structures::sync::Lrc; use std::any::Any; use std::ffi::CString; -use std::sync::Arc; use std::time::{Instant, Duration}; use std::i32; use std::cmp; @@ -557,7 +555,7 @@ fn maybe_create_entry_wrapper(cx: &CodegenCx) { // regions must appear in the argument // listing. let main_ret_ty = cx.tcx.erase_regions( - &main_ret_ty.no_late_bound_regions().unwrap(), + &main_ret_ty.no_bound_vars().unwrap(), ); if declare::get_defined_value(cx, "main").is_some() { @@ -962,128 +960,6 @@ fn assert_and_save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { || rustc_incremental::save_dep_graph(tcx)); } -fn collect_and_partition_mono_items<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - cnum: CrateNum, -) -> (Arc, Arc>>>) -{ - assert_eq!(cnum, LOCAL_CRATE); - - let collection_mode = match tcx.sess.opts.debugging_opts.print_mono_items { - Some(ref s) => { - let mode_string = s.to_lowercase(); - let mode_string = mode_string.trim(); - if mode_string == "eager" { - MonoItemCollectionMode::Eager - } else { - if mode_string != "lazy" { - let message = format!("Unknown codegen-item collection mode '{}'. \ - Falling back to 'lazy' mode.", - mode_string); - tcx.sess.warn(&message); - } - - MonoItemCollectionMode::Lazy - } - } - None => { - if tcx.sess.opts.cg.link_dead_code { - MonoItemCollectionMode::Eager - } else { - MonoItemCollectionMode::Lazy - } - } - }; - - let (items, inlining_map) = - time(tcx.sess, "monomorphization collection", || { - collector::collect_crate_mono_items(tcx, collection_mode) - }); - - tcx.sess.abort_if_errors(); - - ::rustc_mir::monomorphize::assert_symbols_are_distinct(tcx, items.iter()); - - let strategy = if tcx.sess.opts.incremental.is_some() { - PartitioningStrategy::PerModule - } else { - PartitioningStrategy::FixedUnitCount(tcx.sess.codegen_units()) - }; - - let codegen_units = time(tcx.sess, "codegen unit partitioning", || { - partitioning::partition(tcx, - items.iter().cloned(), - strategy, - &inlining_map) - .into_iter() - .map(Arc::new) - .collect::>() - }); - - let mono_items: DefIdSet = items.iter().filter_map(|mono_item| { - match *mono_item { - MonoItem::Fn(ref instance) => Some(instance.def_id()), - MonoItem::Static(def_id) => Some(def_id), - _ => None, - } - }).collect(); - - if tcx.sess.opts.debugging_opts.print_mono_items.is_some() { - let mut item_to_cgus: FxHashMap<_, Vec<_>> = Default::default(); - - for cgu in &codegen_units { - for (&mono_item, &linkage) in cgu.items() { - item_to_cgus.entry(mono_item) - .or_default() - .push((cgu.name().clone(), linkage)); - } - } - - let mut item_keys: Vec<_> = items - .iter() - .map(|i| { - let mut output = i.to_string(tcx); - output.push_str(" @@"); - let mut empty = Vec::new(); - let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty); - cgus.as_mut_slice().sort_by_key(|&(ref name, _)| name.clone()); - cgus.dedup(); - for &(ref cgu_name, (linkage, _)) in cgus.iter() { - output.push_str(" "); - output.push_str(&cgu_name.as_str()); - - let linkage_abbrev = match linkage { - Linkage::External => "External", - Linkage::AvailableExternally => "Available", - Linkage::LinkOnceAny => "OnceAny", - Linkage::LinkOnceODR => "OnceODR", - Linkage::WeakAny => "WeakAny", - Linkage::WeakODR => "WeakODR", - Linkage::Appending => "Appending", - Linkage::Internal => "Internal", - Linkage::Private => "Private", - Linkage::ExternalWeak => "ExternalWeak", - Linkage::Common => "Common", - }; - - output.push_str("["); - output.push_str(linkage_abbrev); - output.push_str("]"); - } - output - }) - .collect(); - - item_keys.sort(); - - for item in item_keys { - println!("MONO_ITEM {}", item); - } - } - - (Arc::new(mono_items), Arc::new(codegen_units)) -} - impl CrateInfo { pub fn new(tcx: TyCtxt) -> CrateInfo { let mut info = CrateInfo { @@ -1173,12 +1049,6 @@ impl CrateInfo { } } -fn is_codegened_item(tcx: TyCtxt, id: DefId) -> bool { - let (all_mono_items, _) = - tcx.collect_and_partition_mono_items(LOCAL_CRATE); - all_mono_items.contains(&id) -} - fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cgu_name: InternedString) -> Stats { @@ -1269,24 +1139,7 @@ fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -pub fn provide(providers: &mut Providers) { - providers.collect_and_partition_mono_items = - collect_and_partition_mono_items; - - providers.is_codegened_item = is_codegened_item; - - providers.codegen_unit = |tcx, name| { - let (_, all) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); - all.iter() - .find(|cgu| *cgu.name() == name) - .cloned() - .unwrap_or_else(|| panic!("failed to find cgu with name {:?}", name)) - }; - - provide_extern(providers); -} - -pub fn provide_extern(providers: &mut Providers) { +pub fn provide_both(providers: &mut Providers) { providers.dllimport_foreign_items = |tcx, krate| { let module_map = tcx.foreign_modules(krate); let module_map = module_map.iter() diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs index 7300bac96182b..c8c693257d52f 100644 --- a/src/librustc_codegen_llvm/callee.rs +++ b/src/librustc_codegen_llvm/callee.rs @@ -44,7 +44,7 @@ pub fn get_fn( debug!("get_fn(instance={:?})", instance); assert!(!instance.substs.needs_infer()); - assert!(!instance.substs.has_escaping_regions()); + assert!(!instance.substs.has_escaping_bound_vars()); assert!(!instance.substs.has_param_types()); let sig = instance.fn_sig(cx.tcx); diff --git a/src/librustc_codegen_llvm/debuginfo/type_names.rs b/src/librustc_codegen_llvm/debuginfo/type_names.rs index f5abb527e430f..eb5ae81b21840 100644 --- a/src/librustc_codegen_llvm/debuginfo/type_names.rs +++ b/src/librustc_codegen_llvm/debuginfo/type_names.rs @@ -173,6 +173,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ty::Infer(_) | ty::UnnormalizedProjection(..) | ty::Projection(..) | + ty::Bound(..) | ty::Opaque(..) | ty::GeneratorWitness(..) | ty::Param(_) => { diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 63a8ab077e5ae..5d9bae5412e1a 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -71,7 +71,6 @@ use back::bytecode::RLIB_BYTECODE_EXTENSION; pub use llvm_util::target_features; use std::any::Any; -use std::path::{PathBuf}; use std::sync::mpsc; use rustc_data_structures::sync::Lrc; @@ -87,20 +86,17 @@ use rustc::util::time_graph; use rustc::util::nodemap::{FxHashSet, FxHashMap}; use rustc::util::profiling::ProfileCategory; use rustc_mir::monomorphize; +use rustc_codegen_utils::{CompiledModule, ModuleKind}; use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc_data_structures::svh::Svh; mod diagnostics; mod back { - pub use rustc_codegen_utils::symbol_names; mod archive; pub mod bytecode; - mod command; - pub mod linker; pub mod link; pub mod lto; - pub mod symbol_export; pub mod write; mod rpath; pub mod wasm; @@ -194,15 +190,15 @@ impl CodegenBackend for LlvmCodegenBackend { } fn provide(&self, providers: &mut ty::query::Providers) { - back::symbol_names::provide(providers); - back::symbol_export::provide(providers); - base::provide(providers); + rustc_codegen_utils::symbol_export::provide(providers); + rustc_codegen_utils::symbol_names::provide(providers); + base::provide_both(providers); attributes::provide(providers); } fn provide_extern(&self, providers: &mut ty::query::Providers) { - back::symbol_export::provide_extern(providers); - base::provide_extern(providers); + rustc_codegen_utils::symbol_export::provide_extern(providers); + base::provide_both(providers); attributes::provide_extern(providers); } @@ -281,13 +277,6 @@ struct CachedModuleCodegen { source: WorkProduct, } -#[derive(Copy, Clone, Debug, PartialEq)] -enum ModuleKind { - Regular, - Metadata, - Allocator, -} - impl ModuleCodegen { fn into_compiled_module(self, emit_obj: bool, @@ -321,15 +310,6 @@ impl ModuleCodegen { } } -#[derive(Debug)] -struct CompiledModule { - name: String, - kind: ModuleKind, - object: Option, - bytecode: Option, - bytecode_compressed: Option, -} - struct ModuleLlvm { llcx: &'static mut llvm::Context, llmod_raw: *const llvm::Module, @@ -377,7 +357,7 @@ struct CodegenResults { crate_hash: Svh, metadata: rustc::middle::cstore::EncodedMetadata, windows_subsystem: Option, - linker_info: back::linker::LinkerInfo, + linker_info: rustc_codegen_utils::linker::LinkerInfo, crate_info: CrateInfo, } diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs index 03ded64e64235..b01d7e3a776f7 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/src/librustc_codegen_llvm/type_of.rs @@ -285,7 +285,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { debug!("llvm_type({:#?})", self); - assert!(!self.ty.has_escaping_regions(), "{:?} has escaping regions", self.ty); + assert!(!self.ty.has_escaping_bound_vars(), "{:?} has escaping bound vars", self.ty); // Make sure lifetimes are erased, to avoid generating distinct LLVM // types for Rust types that only differ in the choice of lifetimes. diff --git a/src/librustc_codegen_utils/Cargo.toml b/src/librustc_codegen_utils/Cargo.toml index a1f4a323f849e..4c57e97841409 100644 --- a/src/librustc_codegen_utils/Cargo.toml +++ b/src/librustc_codegen_utils/Cargo.toml @@ -13,11 +13,13 @@ test = false flate2 = "1.0" log = "0.4" +serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } rustc = { path = "../librustc" } +rustc_allocator = { path = "../librustc_allocator" } rustc_target = { path = "../librustc_target" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_metadata = { path = "../librustc_metadata" } rustc_mir = { path = "../librustc_mir" } rustc_incremental = { path = "../librustc_incremental" } -rustc_metadata_utils = { path = "../librustc_metadata_utils" } diff --git a/src/librustc_codegen_llvm/back/command.rs b/src/librustc_codegen_utils/command.rs similarity index 100% rename from src/librustc_codegen_llvm/back/command.rs rename to src/librustc_codegen_utils/command.rs diff --git a/src/librustc_codegen_utils/lib.rs b/src/librustc_codegen_utils/lib.rs index 03b3b20a4e772..f0ce1e9b0efab 100644 --- a/src/librustc_codegen_utils/lib.rs +++ b/src/librustc_codegen_utils/lib.rs @@ -30,20 +30,28 @@ extern crate flate2; #[macro_use] extern crate log; +extern crate serialize; #[macro_use] extern crate rustc; +extern crate rustc_allocator; extern crate rustc_target; +extern crate rustc_metadata; extern crate rustc_mir; extern crate rustc_incremental; extern crate syntax; extern crate syntax_pos; #[macro_use] extern crate rustc_data_structures; -extern crate rustc_metadata_utils; +use std::path::PathBuf; + +use rustc::session::Session; use rustc::ty::TyCtxt; +pub mod command; pub mod link; +pub mod linker; pub mod codegen_backend; +pub mod symbol_export; pub mod symbol_names; pub mod symbol_names_test; @@ -61,4 +69,43 @@ pub fn check_for_rustc_errors_attr(tcx: TyCtxt) { } } +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum ModuleKind { + Regular, + Metadata, + Allocator, +} + +#[derive(Debug)] +pub struct CompiledModule { + pub name: String, + pub kind: ModuleKind, + pub object: Option, + pub bytecode: Option, + pub bytecode_compressed: Option, +} + +pub fn find_library(name: &str, search_paths: &[PathBuf], sess: &Session) + -> PathBuf { + // On Windows, static libraries sometimes show up as libfoo.a and other + // times show up as foo.lib + let oslibname = format!("{}{}{}", + sess.target.target.options.staticlib_prefix, + name, + sess.target.target.options.staticlib_suffix); + let unixlibname = format!("lib{}.a", name); + + for path in search_paths { + debug!("looking for {} inside {:?}", name, path); + let test = path.join(&oslibname); + if test.exists() { return test } + if oslibname != unixlibname { + let test = path.join(&unixlibname); + if test.exists() { return test } + } + } + sess.fatal(&format!("could not find native static library `{}`, \ + perhaps an -L flag is missing?", name)); +} + __build_diagnostic_array! { librustc_codegen_utils, DIAGNOSTICS } diff --git a/src/librustc_codegen_utils/link.rs b/src/librustc_codegen_utils/link.rs index 66e98793f420d..b11aa687326f2 100644 --- a/src/librustc_codegen_utils/link.rs +++ b/src/librustc_codegen_utils/link.rs @@ -13,7 +13,6 @@ use rustc::session::Session; use std::path::{Path, PathBuf}; use syntax::{ast, attr}; use syntax_pos::Span; -use rustc_metadata_utils::validate_crate_name; pub fn out_filename(sess: &Session, crate_type: config::CrateType, @@ -52,7 +51,7 @@ pub fn find_crate_name(sess: Option<&Session>, attrs: &[ast::Attribute], input: &Input) -> String { let validate = |s: String, span: Option| { - validate_crate_name(sess, &s, span); + ::rustc_metadata::validate_crate_name(sess, &s, span); s }; diff --git a/src/librustc_codegen_llvm/back/linker.rs b/src/librustc_codegen_utils/linker.rs similarity index 98% rename from src/librustc_codegen_llvm/back/linker.rs rename to src/librustc_codegen_utils/linker.rs index e18c8b9dec463..c1f41fd509a14 100644 --- a/src/librustc_codegen_llvm/back/linker.rs +++ b/src/librustc_codegen_utils/linker.rs @@ -15,9 +15,7 @@ use std::io::prelude::*; use std::io::{self, BufWriter}; use std::path::{Path, PathBuf}; -use back::archive; -use back::command::Command; -use back::symbol_export; +use command::Command; use rustc::hir::def_id::{LOCAL_CRATE, CrateNum}; use rustc::middle::dependency_format::Linkage; use rustc::session::Session; @@ -26,7 +24,6 @@ use rustc::session::config::{self, CrateType, OptLevel, DebugInfo, use rustc::ty::TyCtxt; use rustc_target::spec::{LinkerFlavor, LldFlavor}; use serialize::{json, Encoder}; -use llvm_util; /// For all the linkers we support, and information they might /// need out of the shared crate context before we get rid of it. @@ -43,10 +40,13 @@ impl LinkerInfo { } } - pub fn to_linker<'a>(&'a self, - cmd: Command, - sess: &'a Session, - flavor: LinkerFlavor) -> Box { + pub fn to_linker<'a>( + &'a self, + cmd: Command, + sess: &'a Session, + flavor: LinkerFlavor, + target_cpu: &'a str, + ) -> Box { match flavor { LinkerFlavor::Lld(LldFlavor::Link) | LinkerFlavor::Msvc => { @@ -70,6 +70,7 @@ impl LinkerInfo { info: self, hinted_static: false, is_ld: false, + target_cpu, }) as Box } @@ -82,6 +83,7 @@ impl LinkerInfo { info: self, hinted_static: false, is_ld: true, + target_cpu, }) as Box } @@ -144,6 +146,7 @@ pub struct GccLinker<'a> { hinted_static: bool, // Keeps track of the current hinting mode. // Link as ld is_ld: bool, + target_cpu: &'a str, } impl<'a> GccLinker<'a> { @@ -204,7 +207,8 @@ impl<'a> GccLinker<'a> { }; self.linker_arg(&format!("-plugin-opt={}", opt_level)); - self.linker_arg(&format!("-plugin-opt=mcpu={}", llvm_util::target_cpu(self.sess))); + let target_cpu = self.target_cpu; + self.linker_arg(&format!("-plugin-opt=mcpu={}", target_cpu)); match self.sess.lto() { config::Lto::Thin | @@ -263,7 +267,7 @@ impl<'a> Linker for GccLinker<'a> { // -force_load is the macOS equivalent of --whole-archive, but it // involves passing the full path to the library to link. self.linker_arg("-force_load"); - let lib = archive::find_library(lib, search_path, &self.sess); + let lib = ::find_library(lib, search_path, &self.sess); self.linker_arg(&lib); } } @@ -898,7 +902,8 @@ impl<'a> Linker for EmLinker<'a> { fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec { let mut symbols = Vec::new(); - let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); + let export_threshold = + ::symbol_export::crates_export_threshold(&[crate_type]); for &(symbol, level) in tcx.exported_symbols(LOCAL_CRATE).iter() { if level.is_below_threshold(export_threshold) { symbols.push(symbol.symbol_name(tcx).to_string()); diff --git a/src/librustc_codegen_llvm/back/symbol_export.rs b/src/librustc_codegen_utils/symbol_export.rs similarity index 99% rename from src/librustc_codegen_llvm/back/symbol_export.rs rename to src/librustc_codegen_utils/symbol_export.rs index 6b1b0b94fd9d7..2d650f7f18d6f 100644 --- a/src/librustc_codegen_llvm/back/symbol_export.rs +++ b/src/librustc_codegen_utils/symbol_export.rs @@ -11,7 +11,7 @@ use rustc_data_structures::sync::Lrc; use std::sync::Arc; -use monomorphize::Instance; +use rustc::ty::Instance; use rustc::hir; use rustc::hir::Node; use rustc::hir::CodegenFnAttrFlags; diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index f18f40bf7a144..28b7c610a91c0 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -616,22 +616,22 @@ fn escaping() { // Theta = [A -> &'a foo] env.create_simple_region_hierarchy(); - assert!(!env.t_nil().has_escaping_regions()); + assert!(!env.t_nil().has_escaping_bound_vars()); let t_rptr_free1 = env.t_rptr_free(1); - assert!(!t_rptr_free1.has_escaping_regions()); + assert!(!t_rptr_free1.has_escaping_bound_vars()); let t_rptr_bound1 = env.t_rptr_late_bound_with_debruijn(1, d1()); - assert!(t_rptr_bound1.has_escaping_regions()); + assert!(t_rptr_bound1.has_escaping_bound_vars()); let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, d2()); - assert!(t_rptr_bound2.has_escaping_regions()); + assert!(t_rptr_bound2.has_escaping_bound_vars()); // t_fn = fn(A) let t_param = env.t_param(0); - assert!(!t_param.has_escaping_regions()); + assert!(!t_param.has_escaping_bound_vars()); let t_fn = env.t_fn(&[t_param], env.t_nil()); - assert!(!t_fn.has_escaping_regions()); + assert!(!t_fn.has_escaping_bound_vars()); }) } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 5197876f92197..2e19b441d0e39 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -718,6 +718,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::Param(..) | ty::Infer(..) | + ty::Bound(..) | ty::Error | ty::Closure(..) | ty::Generator(..) | diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index 6142fe78149ce..338824d5efe4c 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -20,4 +20,3 @@ serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_ext = { path = "../libsyntax_ext" } syntax_pos = { path = "../libsyntax_pos" } -rustc_metadata_utils = { path = "../librustc_metadata_utils" } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 4b96735eb77b4..7733ab2e246d1 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -30,8 +30,6 @@ use rustc::util::common::record_time; use rustc::util::nodemap::FxHashSet; use rustc::hir::map::Definitions; -use rustc_metadata_utils::validate_crate_name; - use std::ops::Deref; use std::path::PathBuf; use std::{cmp, fs}; @@ -1106,7 +1104,7 @@ impl<'a> CrateLoader<'a> { item.ident, orig_name); let orig_name = match orig_name { Some(orig_name) => { - validate_crate_name(Some(self.sess), &orig_name.as_str(), + ::validate_crate_name(Some(self.sess), &orig_name.as_str(), Some(item.span)); orig_name } diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 7008166b9035d..0cc0707a3a51f 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -38,7 +38,6 @@ extern crate serialize as rustc_serialize; // used by deriving extern crate rustc_errors as errors; extern crate syntax_ext; extern crate proc_macro; -extern crate rustc_metadata_utils; #[macro_use] extern crate rustc; @@ -64,4 +63,34 @@ pub mod cstore; pub mod dynamic_lib; pub mod locator; +pub fn validate_crate_name( + sess: Option<&rustc::session::Session>, + s: &str, + sp: Option +) { + let mut err_count = 0; + { + let mut say = |s: &str| { + match (sp, sess) { + (_, None) => bug!("{}", s), + (Some(sp), Some(sess)) => sess.span_err(sp, s), + (None, Some(sess)) => sess.err(s), + } + err_count += 1; + }; + if s.is_empty() { + say("crate name must not be empty"); + } + for c in s.chars() { + if c.is_alphanumeric() { continue } + if c == '_' { continue } + say(&format!("invalid character `{}` in crate name: `{}`", c, s)); + } + } + + if err_count > 0 { + sess.unwrap().abort_if_errors(); + } +} + __build_diagnostic_array! { librustc_metadata, DIAGNOSTICS } diff --git a/src/librustc_metadata_utils/Cargo.toml b/src/librustc_metadata_utils/Cargo.toml deleted file mode 100644 index 4a5e20376bfb5..0000000000000 --- a/src/librustc_metadata_utils/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_metadata_utils" -version = "0.0.0" - -[lib] -name = "rustc_metadata_utils" -path = "lib.rs" -crate-type = ["dylib"] - -[dependencies] -rustc = { path = "../librustc" } -syntax = { path = "../libsyntax" } -syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_metadata_utils/lib.rs b/src/librustc_metadata_utils/lib.rs deleted file mode 100644 index a1e5150390ac1..0000000000000 --- a/src/librustc_metadata_utils/lib.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[macro_use] -extern crate rustc; -extern crate syntax_pos; - -use rustc::session::Session; -use syntax_pos::Span; - -pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option) { - let mut err_count = 0; - { - let mut say = |s: &str| { - match (sp, sess) { - (_, None) => bug!("{}", s), - (Some(sp), Some(sess)) => sess.span_err(sp, s), - (None, Some(sess)) => sess.err(s), - } - err_count += 1; - }; - if s.is_empty() { - say("crate name must not be empty"); - } - for c in s.chars() { - if c.is_alphanumeric() { continue } - if c == '_' { continue } - say(&format!("invalid character `{}` in crate name: `{}`", c, s)); - } - } - - if err_count > 0 { - sess.unwrap().abort_if_errors(); - } -} diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs index 2b671891fca6d..99372a511a9de 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs @@ -277,8 +277,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { | ty::RePlaceholder(..) | ty::ReEmpty | ty::ReErased - | ty::ReClosureBound(..) - | ty::ReCanonical(..) => None, + | ty::ReClosureBound(..) => None, } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs index 994f20a011d65..44566206820cd 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs @@ -82,9 +82,9 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> { // when we move to universes, we will, and this assertion // will start to fail. let ty::OutlivesPredicate(k1, r2) = - query_constraint.no_late_bound_regions().unwrap_or_else(|| { + query_constraint.no_bound_vars().unwrap_or_else(|| { bug!( - "query_constraint {:?} contained bound regions", + "query_constraint {:?} contained bound vars", query_constraint, ); }); diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 3098acffa23dc..5c1585e324939 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -359,7 +359,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { } fn sanitize_type(&mut self, parent: &dyn fmt::Debug, ty: Ty<'tcx>) -> Ty<'tcx> { - if ty.has_escaping_regions() || ty.references_error() { + if ty.has_escaping_bound_vars() || ty.references_error() { span_mirbug_and_err!(self, parent, "bad type {:?}", ty) } else { ty @@ -2184,8 +2184,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { .enumerate() .filter_map(|(idx, constraint)| { let ty::OutlivesPredicate(k1, r2) = - constraint.no_late_bound_regions().unwrap_or_else(|| { - bug!("query_constraint {:?} contained bound regions", constraint,); + constraint.no_bound_vars().unwrap_or_else(|| { + bug!("query_constraint {:?} contained bound vars", constraint,); }); match k1.unpack() { diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index ff3fdffcd7622..f073ae95678ac 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -737,6 +737,11 @@ where if self.alloc_map.contains_key(&alloc) { // Not yet interned, so proceed recursively self.intern_static(alloc, mutability)?; + } else if self.dead_alloc_map.contains_key(&alloc) { + // dangling pointer + return err!(ValidationFailure( + "encountered dangling pointer in final constant".into(), + )) } } Ok(()) diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index aaa97e3372653..8c4e7c6ae9b84 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -94,6 +94,7 @@ pub fn provide(providers: &mut Providers) { borrow_check::provide(providers); shim::provide(providers); transform::provide(providers); + monomorphize::partitioning::provide(providers); providers.const_eval = const_eval::const_eval_provider; providers.const_eval_raw = const_eval::const_eval_raw_provider; providers.check_match = hair::pattern::check_match; diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 8c6966691328a..8e27635dee8c1 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -905,12 +905,12 @@ fn create_mono_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_ty: Ty<'tcx>, impl_ty: Ty<'tcx>, output: &mut Vec>) { - assert!(!trait_ty.needs_subst() && !trait_ty.has_escaping_regions() && - !impl_ty.needs_subst() && !impl_ty.has_escaping_regions()); + assert!(!trait_ty.needs_subst() && !trait_ty.has_escaping_bound_vars() && + !impl_ty.needs_subst() && !impl_ty.has_escaping_bound_vars()); if let ty::Dynamic(ref trait_ty, ..) = trait_ty.sty { let poly_trait_ref = trait_ty.principal().with_self_ty(tcx, impl_ty); - assert!(!poly_trait_ref.has_escaping_regions()); + assert!(!poly_trait_ref.has_escaping_bound_vars()); // Walk all methods of the trait, including those of its supertraits let methods = tcx.vtable_methods(poly_trait_ref); @@ -1082,7 +1082,7 @@ impl<'b, 'a, 'v> RootCollector<'b, 'a, 'v> { // regions must appear in the argument // listing. let main_ret_ty = self.tcx.erase_regions( - &main_ret_ty.no_late_bound_regions().unwrap(), + &main_ret_ty.no_bound_vars().unwrap(), ); let start_instance = Instance::resolve( diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 4c4d56c893838..9d69a5669b1c0 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -382,6 +382,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { self.push_type_params(substs, iter::empty(), output); } ty::Error | + ty::Bound(..) | ty::Infer(_) | ty::UnnormalizedProjection(..) | ty::Projection(..) | diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index f0a35ca7adbd2..2c2bfc995e4d7 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -102,21 +102,27 @@ //! source-level module, functions from the same module will be available for //! inlining, even when they are not marked #[inline]. -use monomorphize::collector::InliningMap; +use std::collections::hash_map::Entry; +use std::cmp; +use std::sync::Arc; + +use syntax::ast::NodeId; +use syntax::symbol::InternedString; use rustc::dep_graph::{WorkProductId, WorkProduct, DepNode, DepConstructor}; use rustc::hir::CodegenFnAttrFlags; -use rustc::hir::def_id::{DefId, LOCAL_CRATE, CRATE_DEF_INDEX}; +use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX}; use rustc::hir::map::DefPathData; use rustc::mir::mono::{Linkage, Visibility, CodegenUnitNameBuilder}; use rustc::middle::exported_symbols::SymbolExportLevel; use rustc::ty::{self, TyCtxt, InstanceDef}; use rustc::ty::item_path::characteristic_def_id_of_type; -use rustc::util::nodemap::{FxHashMap, FxHashSet}; -use std::collections::hash_map::Entry; -use std::cmp; -use syntax::ast::NodeId; -use syntax::symbol::InternedString; +use rustc::ty::query::Providers; +use rustc::util::common::time; +use rustc::util::nodemap::{DefIdSet, FxHashMap, FxHashSet}; use rustc::mir::mono::MonoItem; + +use monomorphize::collector::InliningMap; +use monomorphize::collector::{self, MonoItemCollectionMode}; use monomorphize::item::{MonoItemExt, InstantiationMode}; pub use rustc::mir::mono::CodegenUnit; @@ -892,3 +898,146 @@ fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } } + +fn collect_and_partition_mono_items<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + cnum: CrateNum, +) -> (Arc, Arc>>>) +{ + assert_eq!(cnum, LOCAL_CRATE); + + let collection_mode = match tcx.sess.opts.debugging_opts.print_mono_items { + Some(ref s) => { + let mode_string = s.to_lowercase(); + let mode_string = mode_string.trim(); + if mode_string == "eager" { + MonoItemCollectionMode::Eager + } else { + if mode_string != "lazy" { + let message = format!("Unknown codegen-item collection mode '{}'. \ + Falling back to 'lazy' mode.", + mode_string); + tcx.sess.warn(&message); + } + + MonoItemCollectionMode::Lazy + } + } + None => { + if tcx.sess.opts.cg.link_dead_code { + MonoItemCollectionMode::Eager + } else { + MonoItemCollectionMode::Lazy + } + } + }; + + let (items, inlining_map) = + time(tcx.sess, "monomorphization collection", || { + collector::collect_crate_mono_items(tcx, collection_mode) + }); + + tcx.sess.abort_if_errors(); + + ::monomorphize::assert_symbols_are_distinct(tcx, items.iter()); + + let strategy = if tcx.sess.opts.incremental.is_some() { + PartitioningStrategy::PerModule + } else { + PartitioningStrategy::FixedUnitCount(tcx.sess.codegen_units()) + }; + + let codegen_units = time(tcx.sess, "codegen unit partitioning", || { + partition( + tcx, + items.iter().cloned(), + strategy, + &inlining_map + ) + .into_iter() + .map(Arc::new) + .collect::>() + }); + + let mono_items: DefIdSet = items.iter().filter_map(|mono_item| { + match *mono_item { + MonoItem::Fn(ref instance) => Some(instance.def_id()), + MonoItem::Static(def_id) => Some(def_id), + _ => None, + } + }).collect(); + + if tcx.sess.opts.debugging_opts.print_mono_items.is_some() { + let mut item_to_cgus: FxHashMap<_, Vec<_>> = Default::default(); + + for cgu in &codegen_units { + for (&mono_item, &linkage) in cgu.items() { + item_to_cgus.entry(mono_item) + .or_default() + .push((cgu.name().clone(), linkage)); + } + } + + let mut item_keys: Vec<_> = items + .iter() + .map(|i| { + let mut output = i.to_string(tcx); + output.push_str(" @@"); + let mut empty = Vec::new(); + let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty); + cgus.as_mut_slice().sort_by_key(|&(ref name, _)| name.clone()); + cgus.dedup(); + for &(ref cgu_name, (linkage, _)) in cgus.iter() { + output.push_str(" "); + output.push_str(&cgu_name.as_str()); + + let linkage_abbrev = match linkage { + Linkage::External => "External", + Linkage::AvailableExternally => "Available", + Linkage::LinkOnceAny => "OnceAny", + Linkage::LinkOnceODR => "OnceODR", + Linkage::WeakAny => "WeakAny", + Linkage::WeakODR => "WeakODR", + Linkage::Appending => "Appending", + Linkage::Internal => "Internal", + Linkage::Private => "Private", + Linkage::ExternalWeak => "ExternalWeak", + Linkage::Common => "Common", + }; + + output.push_str("["); + output.push_str(linkage_abbrev); + output.push_str("]"); + } + output + }) + .collect(); + + item_keys.sort(); + + for item in item_keys { + println!("MONO_ITEM {}", item); + } + } + + (Arc::new(mono_items), Arc::new(codegen_units)) +} + +pub fn provide(providers: &mut Providers) { + providers.collect_and_partition_mono_items = + collect_and_partition_mono_items; + + providers.is_codegened_item = |tcx, def_id| { + let (all_mono_items, _) = + tcx.collect_and_partition_mono_items(LOCAL_CRATE); + all_mono_items.contains(&def_id) + }; + + providers.codegen_unit = |tcx, name| { + let (_, all) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); + all.iter() + .find(|cgu| *cgu.name() == name) + .cloned() + .unwrap_or_else(|| panic!("failed to find cgu with name {:?}", name)) + }; +} diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 7061504cd0ae7..76a8501fb177a 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -844,7 +844,9 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, let param_env = gcx.param_env(def_id); // Normalize the sig. - let sig = gcx.fn_sig(def_id).no_late_bound_regions().expect("LBR in ADT constructor signature"); + let sig = gcx.fn_sig(def_id) + .no_bound_vars() + .expect("LBR in ADT constructor signature"); let sig = gcx.normalize_erasing_regions(param_env, sig); let (adt_def, substs) = match sig.output().sty { diff --git a/src/librustc_mir/transform/lower_128bit.rs b/src/librustc_mir/transform/lower_128bit.rs index bd7d9d367618b..80072153167f3 100644 --- a/src/librustc_mir/transform/lower_128bit.rs +++ b/src/librustc_mir/transform/lower_128bit.rs @@ -143,7 +143,7 @@ fn check_lang_item_type<'a, 'tcx, D>( { let did = tcx.require_lang_item(lang_item); let poly_sig = tcx.fn_sig(did); - let sig = poly_sig.no_late_bound_regions().unwrap(); + let sig = poly_sig.no_bound_vars().unwrap(); let lhs_ty = lhs.ty(local_decls, tcx); let rhs_ty = rhs.ty(local_decls, tcx); let place_ty = place.ty(local_decls, tcx).to_ty(tcx); diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 52c557b83d591..6ab68789c027b 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -317,7 +317,8 @@ fn check_terminator( check_place(tcx, mir, location, span, PlaceMode::Read)?; check_operand(tcx, mir, value, span) }, - TerminatorKind::SwitchInt { .. } => Err(( + + TerminatorKind::FalseEdges { .. } | TerminatorKind::SwitchInt { .. } => Err(( span, "`if`, `match`, `&&` and `||` are not stable in const fn".into(), )), @@ -363,7 +364,7 @@ fn check_terminator( cleanup: _, } => check_operand(tcx, mir, cond, span), - | TerminatorKind::FalseEdges { .. } | TerminatorKind::FalseUnwind { .. } => span_bug!( + | TerminatorKind::FalseUnwind { .. } => span_bug!( terminator.source_info.span, "min_const_fn encountered `{:#?}`", terminator diff --git a/src/librustc_resolve/error_reporting.rs b/src/librustc_resolve/error_reporting.rs index d77b1868ed72e..52848fbb3b112 100644 --- a/src/librustc_resolve/error_reporting.rs +++ b/src/librustc_resolve/error_reporting.rs @@ -24,7 +24,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { &mut self, span: Span, path: Vec - ) -> Option> { + ) -> Option<(Vec, Option)> { debug!("make_path_suggestion: span={:?} path={:?}", span, path); // If we don't have a path to suggest changes to, then return. if path.is_empty() { @@ -60,13 +60,13 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { &mut self, span: Span, mut path: Vec - ) -> Option> { + ) -> Option<(Vec, Option)> { // Replace first ident with `self` and check if that is valid. path[0].ident.name = keywords::SelfValue.name(); let result = self.resolve_path(None, &path, None, false, span, CrateLint::No); debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result); if let PathResult::Module(..) = result { - Some(path) + Some((path, None)) } else { None } @@ -83,13 +83,20 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { &mut self, span: Span, mut path: Vec - ) -> Option> { + ) -> Option<(Vec, Option)> { // Replace first ident with `crate` and check if that is valid. path[0].ident.name = keywords::Crate.name(); let result = self.resolve_path(None, &path, None, false, span, CrateLint::No); debug!("make_missing_crate_suggestion: path={:?} result={:?}", path, result); if let PathResult::Module(..) = result { - Some(path) + Some(( + path, + Some( + "`use` statements changed in Rust 2018; read more at \ + ".to_string() + ), + )) } else { None } @@ -106,13 +113,13 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { &mut self, span: Span, mut path: Vec - ) -> Option> { + ) -> Option<(Vec, Option)> { // Replace first ident with `crate` and check if that is valid. path[0].ident.name = keywords::Super.name(); let result = self.resolve_path(None, &path, None, false, span, CrateLint::No); debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result); if let PathResult::Module(..) = result { - Some(path) + Some((path, None)) } else { None } @@ -132,7 +139,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { &mut self, span: Span, mut path: Vec - ) -> Option> { + ) -> Option<(Vec, Option)> { // Need to clone else we can't call `resolve_path` without a borrow error. We also store // into a `BTreeMap` so we can get consistent ordering (and therefore the same diagnostic) // each time. @@ -153,7 +160,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}", name, path, result); if let PathResult::Module(..) = result { - return Some(path) + return Some((path, None)); } } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 810aff7f9b0a8..85686c03c2da8 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -703,7 +703,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { } } }); - } else if let Some((span, err)) = error { + } else if let Some((span, err, note)) = error { errors = true; if let SingleImport { source, ref result, .. } = import.subclass { @@ -733,7 +733,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { &import.subclass, span, ); - error_vec.push((span, path, err)); + error_vec.push((span, path, err, note)); seen_spans.insert(span); prev_root_id = import.root_id; } @@ -825,27 +825,45 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { } } - fn throw_unresolved_import_error(&self, error_vec: Vec<(Span, String, String)>, - span: Option) { + fn throw_unresolved_import_error( + &self, + error_vec: Vec<(Span, String, String, Option)>, + span: Option, + ) { let max_span_label_msg_count = 10; // upper limit on number of span_label message. - let (span, msg) = if error_vec.is_empty() { - (span.unwrap(), "unresolved import".to_string()) + let (span, msg, note) = if error_vec.is_empty() { + (span.unwrap(), "unresolved import".to_string(), None) } else { - let span = MultiSpan::from_spans(error_vec.clone().into_iter() - .map(|elem: (Span, String, String)| { elem.0 }) - .collect()); + let span = MultiSpan::from_spans( + error_vec.clone().into_iter() + .map(|elem: (Span, String, String, Option)| elem.0) + .collect() + ); + + let note: Option = error_vec.clone().into_iter() + .filter_map(|elem: (Span, String, String, Option)| elem.3) + .last(); + let path_vec: Vec = error_vec.clone().into_iter() - .map(|elem: (Span, String, String)| { format!("`{}`", elem.1) }) + .map(|elem: (Span, String, String, Option)| format!("`{}`", elem.1)) .collect(); let path = path_vec.join(", "); - let msg = format!("unresolved import{} {}", - if path_vec.len() > 1 { "s" } else { "" }, path); - (span, msg) + let msg = format!( + "unresolved import{} {}", + if path_vec.len() > 1 { "s" } else { "" }, + path + ); + + (span, msg, note) }; + let mut err = struct_span_err!(self.resolver.session, span, E0432, "{}", &msg); for span_error in error_vec.into_iter().take(max_span_label_msg_count) { err.span_label(span_error.0, span_error.2); } + if let Some(note) = note { + err.note(¬e); + } err.emit(); } @@ -941,7 +959,10 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { } // If appropriate, returns an error to report. - fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Span, String)> { + fn finalize_import( + &mut self, + directive: &'b ImportDirective<'b> + ) -> Option<(Span, String, Option)> { self.current_module = directive.parent; let ImportDirective { ref module_path, span, .. } = *directive; @@ -964,15 +985,16 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { return None; } PathResult::Failed(span, msg, true) => { - return if let Some(suggested_path) = self.make_path_suggestion( + return if let Some((suggested_path, note)) = self.make_path_suggestion( span, module_path.clone() ) { Some(( span, - format!("Did you mean `{}`?", Segment::names_to_string(&suggested_path)) + format!("Did you mean `{}`?", Segment::names_to_string(&suggested_path)), + note, )) } else { - Some((span, msg)) + Some((span, msg, None)) }; }, _ => return None, @@ -997,8 +1019,11 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { if let ModuleOrUniformRoot::Module(module) = module { if module.def_id() == directive.parent.def_id() { // Importing a module into itself is not allowed. - return Some((directive.span, - "Cannot glob-import a module into itself.".to_string())); + return Some(( + directive.span, + "Cannot glob-import a module into itself.".to_string(), + None, + )); } } if !is_prelude && @@ -1096,7 +1121,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { } } }; - Some((span, msg)) + Some((span, msg, None)) } else { // `resolve_ident_in_module` reported a privacy error. self.import_dummy_binding(directive); diff --git a/src/librustc_traits/chalk_context.rs b/src/librustc_traits/chalk_context.rs index 5d6badf120286..bf252053199f8 100644 --- a/src/librustc_traits/chalk_context.rs +++ b/src/librustc_traits/chalk_context.rs @@ -506,6 +506,7 @@ impl context::UnificationOps, ChalkArenas<'tcx>> ty::GeneratorWitness(..) | ty::UnnormalizedProjection(..) | ty::Infer(..) | + ty::Bound(..) | ty::Error => { bug!("unexpected type {:?}", ty) } diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs index 2ad7ab7c4d927..af64522f18398 100644 --- a/src/librustc_traits/dropck_outlives.rs +++ b/src/librustc_traits/dropck_outlives.rs @@ -274,7 +274,7 @@ fn dtorck_constraint_for_ty<'a, 'gcx, 'tcx>( ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), - ty::Infer(..) | ty::Error => { + ty::Bound(..) | ty::Infer(..) | ty::Error => { // By the time this code runs, all type variables ought to // be fully resolved. Err(NoSolution) diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs index ad0a54e392f58..3c2ef1ae6d19f 100644 --- a/src/librustc_traits/implied_outlives_bounds.rs +++ b/src/librustc_traits/implied_outlives_bounds.rs @@ -108,7 +108,7 @@ fn compute_implied_outlives_bounds<'tcx>( // From the full set of obligations, just filter down to the // region relationships. implied_bounds.extend(obligations.into_iter().flat_map(|obligation| { - assert!(!obligation.has_escaping_regions()); + assert!(!obligation.has_escaping_bound_vars()); match obligation.predicate { ty::Predicate::Trait(..) | ty::Predicate::Subtype(..) | @@ -122,14 +122,14 @@ fn compute_implied_outlives_bounds<'tcx>( vec![] } - ty::Predicate::RegionOutlives(ref data) => match data.no_late_bound_regions() { + ty::Predicate::RegionOutlives(ref data) => match data.no_bound_vars() { None => vec![], Some(ty::OutlivesPredicate(r_a, r_b)) => { vec![OutlivesBound::RegionSubRegion(r_b, r_a)] } }, - ty::Predicate::TypeOutlives(ref data) => match data.no_late_bound_regions() { + ty::Predicate::TypeOutlives(ref data) => match data.no_bound_vars() { None => vec![], Some(ty::OutlivesPredicate(ty_a, r_b)) => { let ty_a = infcx.resolve_type_vars_if_possible(&ty_a); diff --git a/src/librustc_traits/lowering/environment.rs b/src/librustc_traits/lowering/environment.rs index c71898f73ecad..052ca37b31371 100644 --- a/src/librustc_traits/lowering/environment.rs +++ b/src/librustc_traits/lowering/environment.rs @@ -93,6 +93,7 @@ impl ClauseVisitor<'set, 'a, 'tcx> { ty::GeneratorWitness(..) | ty::UnnormalizedProjection(..) | ty::Infer(..) | + ty::Bound(..) | ty::Error => { bug!("unexpected type {:?}", ty); } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1978f86545e7b..229bcab9bd890 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1748,7 +1748,7 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> { self.region_bounds.iter().map(|&(region_bound, span)| { // account for the binder being introduced below; no need to shift `param_ty` // because, at present at least, it can only refer to early-bound regions - let region_bound = tcx.mk_region(ty::fold::shift_region(*region_bound, 1)); + let region_bound = ty::fold::shift_region(tcx, region_bound, 1); let outlives = ty::OutlivesPredicate(param_ty, region_bound); (ty::Binder::dummy(outlives).to_predicate(), span) }).chain( diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 3204ef556f5dd..40f2072079a5a 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -816,7 +816,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); } // Replace constructor type with constructed type for tuple struct patterns. let pat_ty = pat_ty.fn_sig(tcx).output(); - let pat_ty = pat_ty.no_late_bound_regions().expect("expected fn type"); + let pat_ty = pat_ty.no_bound_vars().expect("expected fn type"); self.demand_eqtype(pat.span, expected, pat_ty); diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index e0ee26cba0828..3f0a353124442 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -128,7 +128,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty::Opaque(def_id, substs) => Some(PointerKind::OfOpaque(def_id, substs)), ty::Param(ref p) => Some(PointerKind::OfParam(p)), // Insufficient type information. - ty::Infer(_) => None, + ty::Bound(..) | ty::Infer(_) => None, ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) | ty::Float(_) | ty::Array(..) | ty::GeneratorWitness(..) | diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 3f4d187813d5d..5a758ab642bac 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -458,7 +458,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Create a `PolyFnSig`. Note the oddity that late bound // regions appearing free in `expected_sig` are now bound up // in this binder we are creating. - assert!(!expected_sig.sig.has_regions_bound_above(ty::INNERMOST)); + assert!(!expected_sig.sig.has_vars_bound_above(ty::INNERMOST)); let bound_sig = ty::Binder::bind(self.tcx.mk_fn_sig( expected_sig.sig.inputs().iter().cloned(), expected_sig.sig.output(), diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index da96d4f0cba42..3156458b4aa4a 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -419,7 +419,7 @@ pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut structural_to_nomimal = FxHashMap::default(); let sig = tcx.fn_sig(def_id); - let sig = sig.no_late_bound_regions().unwrap(); + let sig = sig.no_bound_vars().unwrap(); if intr.inputs.len() != sig.inputs().len() { span_err!(tcx.sess, it.span, E0444, "platform-specific intrinsic has invalid number of \ diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 04c32fa88271a..11448750618e2 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -331,7 +331,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { value } }; - assert!(!bounds.has_escaping_regions()); + assert!(!bounds.has_escaping_bound_vars()); let cause = traits::ObligationCause::misc(span, self.body_id); obligations.extend(traits::predicates_for_generics(cause.clone(), diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index c506f23078f25..6ed36359a036b 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1373,7 +1373,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn_sig, substs); - assert!(!substs.has_escaping_regions()); + assert!(!substs.has_escaping_bound_vars()); // It is possible for type parameters or early-bound lifetimes // to appear in the signature of `self`. The substitutions we diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7e25694d5598f..e120d71e304b8 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -653,8 +653,8 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) { debug!("register_predicate({:?})", obligation); - if obligation.has_escaping_regions() { - span_bug!(obligation.cause.span, "escaping regions in predicate {:?}", + if obligation.has_escaping_bound_vars() { + span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation); } self.fulfillment_cx @@ -1928,7 +1928,7 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { } fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - if ty.has_escaping_regions() { + if ty.has_escaping_bound_vars() { ty // FIXME: normalization and escaping regions } else { self.normalize_associated_types_in(span, &ty) @@ -2431,7 +2431,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { cause: traits::ObligationCause<'tcx>, predicates: &ty::InstantiatedPredicates<'tcx>) { - assert!(!predicates.has_escaping_regions()); + assert!(!predicates.has_escaping_bound_vars()); debug!("add_obligations_for_parameters(predicates={:?})", predicates); @@ -5191,8 +5191,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }, ); - assert!(!substs.has_escaping_regions()); - assert!(!ty.has_escaping_regions()); + assert!(!substs.has_escaping_bound_vars()); + assert!(!ty.has_escaping_bound_vars()); // Write the "user substs" down first thing for later. let hir_id = self.tcx.hir.node_to_hir_id(node_id); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 9990d2ee2b676..ea84e874b1a5b 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -13,7 +13,7 @@ use constrained_type_params::{identify_constrained_type_params, Parameter}; use hir::def_id::DefId; use rustc::traits::{self, ObligationCauseCode}; -use rustc::ty::{self, Lift, Ty, TyCtxt, GenericParamDefKind, TypeFoldable}; +use rustc::ty::{self, Lift, Ty, TyCtxt, TyKind, GenericParamDefKind, TypeFoldable}; use rustc::ty::subst::{Subst, Substs}; use rustc::ty::util::ExplicitSelf; use rustc::util::nodemap::{FxHashSet, FxHashMap}; @@ -119,14 +119,14 @@ pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: Def check_item_fn(tcx, item); } hir::ItemKind::Static(ref ty, ..) => { - check_item_type(tcx, item.id, ty.span); + check_item_type(tcx, item.id, ty.span, false); } hir::ItemKind::Const(ref ty, ..) => { - check_item_type(tcx, item.id, ty.span); + check_item_type(tcx, item.id, ty.span, false); } hir::ItemKind::ForeignMod(ref module) => for it in module.items.iter() { if let hir::ForeignItemKind::Static(ref ty, ..) = it.node { - check_item_type(tcx, it.id, ty.span); + check_item_type(tcx, it.id, ty.span, true); } }, hir::ItemKind::Struct(ref struct_def, ref ast_generics) => { @@ -340,23 +340,33 @@ fn check_item_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) { }) } -fn check_item_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId, ty_span: Span) { +fn check_item_type<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + item_id: ast::NodeId, + ty_span: Span, + allow_foreign_ty: bool, +) { debug!("check_item_type: {:?}", item_id); for_id(tcx, item_id, ty_span).with_fcx(|fcx, _this| { let ty = fcx.tcx.type_of(fcx.tcx.hir.local_def_id(item_id)); let item_ty = fcx.normalize_associated_types_in(ty_span, &ty); + let mut forbid_unsized = true; + if allow_foreign_ty { + if let TyKind::Foreign(_) = tcx.struct_tail(item_ty).sty { + forbid_unsized = false; + } + } + fcx.register_wf_obligation(item_ty, ty_span, ObligationCauseCode::MiscObligation); - fcx.register_bound( - item_ty, - fcx.tcx.require_lang_item(lang_items::SizedTraitLangItem), - traits::ObligationCause::new( - ty_span, - fcx.body_id, - traits::MiscObligation, - ), - ); + if forbid_unsized { + fcx.register_bound( + item_ty, + fcx.tcx.require_lang_item(lang_items::SizedTraitLangItem), + traits::ObligationCause::new(ty_span, fcx.body_id, traits::MiscObligation), + ); + } vec![] // no implied bounds in a const etc }); diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 05a83dd307c38..24632c0bd2b8c 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -98,7 +98,7 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_did: let span = tcx.hir.span(impl_node_id); let param_env = tcx.param_env(impl_did); - assert!(!self_type.has_escaping_regions()); + assert!(!self_type.has_escaping_bound_vars()); debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type); @@ -187,7 +187,7 @@ pub fn coerce_unsized_info<'a, 'gcx>(gcx: TyCtxt<'a, 'gcx, 'gcx>, let span = gcx.hir.span(impl_node_id); let param_env = gcx.param_env(impl_did); - assert!(!source.has_escaping_regions()); + assert!(!source.has_escaping_bound_vars()); let err_info = CoerceUnsizedInfo { custom_kind: None }; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index eb52a013b0566..bf3887ee8fcdd 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -208,7 +208,7 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { item_def_id: DefId, poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Ty<'tcx> { - if let Some(trait_ref) = poly_trait_ref.no_late_bound_regions() { + if let Some(trait_ref) = poly_trait_ref.no_bound_vars() { self.tcx().mk_projection(item_def_id, trait_ref.substs) } else { // no late-bound regions, we can just ignore the binder diff --git a/src/librustc_typeck/outlives/utils.rs b/src/librustc_typeck/outlives/utils.rs index 96b75c4792d75..d748d93d8988e 100644 --- a/src/librustc_typeck/outlives/utils.rs +++ b/src/librustc_typeck/outlives/utils.rs @@ -167,7 +167,6 @@ fn is_free_region<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, region: Region<'_>) -> bool RegionKind::ReEmpty | RegionKind::ReErased | RegionKind::ReClosureBound(..) - | RegionKind::ReCanonical(..) | RegionKind::ReScope(..) | RegionKind::ReVar(..) | RegionKind::RePlaceholder(..) diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 3e523c0c7f559..47d34c909961e 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -338,6 +338,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { ty::UnnormalizedProjection(..) | ty::GeneratorWitness(..) | + ty::Bound(..) | ty::Infer(..) => { bug!("unexpected type encountered in \ variance inference: {}", @@ -426,7 +427,6 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // way early-bound regions do, so we skip them here. } - ty::ReCanonical(_) | ty::ReFree(..) | ty::ReClosureBound(..) | ty::ReScope(..) | diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 88240e844edc2..e71b3ccb01dbe 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1260,7 +1260,6 @@ impl Clean> for ty::RegionKind { ty::RePlaceholder(..) | ty::ReEmpty | ty::ReClosureBound(_) | - ty::ReCanonical(_) | ty::ReErased => None } } @@ -2733,6 +2732,7 @@ impl<'tcx> Clean for Ty<'tcx> { ty::Closure(..) | ty::Generator(..) => Tuple(vec![]), // FIXME(pcwalton) + ty::Bound(..) => panic!("Bound"), ty::UnnormalizedProjection(..) => panic!("UnnormalizedProjection"), ty::GeneratorWitness(..) => panic!("GeneratorWitness"), ty::Infer(..) => panic!("Infer"), diff --git a/src/libstd/path.rs b/src/libstd/path.rs index ca8be75fab5be..a153456370c6f 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -87,6 +87,8 @@ use io; use iter::{self, FusedIterator}; use ops::{self, Deref}; use rc::Rc; +use str::FromStr; +use string::ParseError; use sync::Arc; use ffi::{OsStr, OsString}; @@ -1443,6 +1445,15 @@ impl From for PathBuf { } } +#[stable(feature = "path_from_str", since = "1.26.0")] +impl FromStr for PathBuf { + type Err = ParseError; + + fn from_str(s: &str) -> Result { + Ok(PathBuf::from(s)) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl> iter::FromIterator

for PathBuf { fn from_iter>(iter: I) -> PathBuf { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 2cd4fd92bc81e..da0ec33030e06 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -504,6 +504,9 @@ declare_features! ( // `extern crate foo as bar;` puts `bar` into extern prelude. (active, extern_crate_item_prelude, "1.31.0", Some(54658), None), + + // `reason = ` in lint attributes and `expect` lint attribute + (active, lint_reasons, "1.31.0", Some(54503), None), ); declare_features! ( diff --git a/src/test/ui/consts/dangling-alloc-id-ice-2.nll.stderr b/src/test/ui/consts/dangling-alloc-id-ice-2.nll.stderr new file mode 100644 index 0000000000000..e6ae57796055f --- /dev/null +++ b/src/test/ui/consts/dangling-alloc-id-ice-2.nll.stderr @@ -0,0 +1,30 @@ +warning[E0716]: temporary value dropped while borrowed + --> $DIR/dangling-alloc-id-ice-2.rs:5:28 + | +LL | static MAP: Slice = Slice(&[ + | ___________________________-^ + | |___________________________| + | || +LL | || b"CloseEvent" as &'static [u8], +LL | || ]); + | || -- temporary value is freed at the end of this statement + | ||_| + | |__creates a temporary which is freed while still in use + | cast requires that borrow lasts for `'static` + | + = warning: This error has been downgraded to a warning for backwards compatibility with previous releases. + It represents potential unsoundness in your code. + This warning will become a hard error in the future. + +error[E0080]: could not evaluate static initializer + --> $DIR/dangling-alloc-id-ice-2.rs:5:1 + | +LL | / static MAP: Slice = Slice(&[ +LL | | b"CloseEvent" as &'static [u8], +LL | | ]); + | |___^ type validation failed: encountered dangling pointer in final constant + +error: aborting due to previous error + +Some errors occurred: E0080, E0716. +For more information about an error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/dangling-alloc-id-ice-2.rs b/src/test/ui/consts/dangling-alloc-id-ice-2.rs new file mode 100644 index 0000000000000..b4691641fc98f --- /dev/null +++ b/src/test/ui/consts/dangling-alloc-id-ice-2.rs @@ -0,0 +1,10 @@ +// FIXME(#55223) this is just a reproduction test showing the wrong behavior + +struct Slice(&'static [&'static [u8]]); + +static MAP: Slice = Slice(&[ + b"CloseEvent" as &'static [u8], +]); + + +fn main() {} diff --git a/src/test/ui/consts/dangling-alloc-id-ice-2.stderr b/src/test/ui/consts/dangling-alloc-id-ice-2.stderr new file mode 100644 index 0000000000000..42df542f55cf5 --- /dev/null +++ b/src/test/ui/consts/dangling-alloc-id-ice-2.stderr @@ -0,0 +1,11 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/dangling-alloc-id-ice-2.rs:5:1 + | +LL | / static MAP: Slice = Slice(&[ +LL | | b"CloseEvent" as &'static [u8], +LL | | ]); + | |___^ type validation failed: encountered dangling pointer in final constant + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/dangling-alloc-id-ice.rs b/src/test/ui/consts/dangling-alloc-id-ice.rs new file mode 100644 index 0000000000000..695d33b690898 --- /dev/null +++ b/src/test/ui/consts/dangling-alloc-id-ice.rs @@ -0,0 +1,15 @@ +// https://github.com/rust-lang/rust/issues/55223 + +#![feature(const_let)] + +union Foo<'a> { + y: &'a (), + long_live_the_unit: &'static (), +} + +const FOO: &() = { //~ ERROR any use of this value will cause an error + let y = (); + unsafe { Foo { y: &y }.long_live_the_unit } +}; + +fn main() {} diff --git a/src/test/ui/consts/dangling-alloc-id-ice.stderr b/src/test/ui/consts/dangling-alloc-id-ice.stderr new file mode 100644 index 0000000000000..a5fa88e5e6832 --- /dev/null +++ b/src/test/ui/consts/dangling-alloc-id-ice.stderr @@ -0,0 +1,13 @@ +error: any use of this value will cause an error + --> $DIR/dangling-alloc-id-ice.rs:10:1 + | +LL | / const FOO: &() = { //~ ERROR any use of this value will cause an error +LL | | let y = (); +LL | | unsafe { Foo { y: &y }.long_live_the_unit } +LL | | }; + | |__^ type validation failed: encountered dangling pointer in final constant + | + = note: #[deny(const_err)] on by default + +error: aborting due to previous error + diff --git a/src/test/ui/consts/dangling_raw_ptr.rs b/src/test/ui/consts/dangling_raw_ptr.rs new file mode 100644 index 0000000000000..7fc773412f2f8 --- /dev/null +++ b/src/test/ui/consts/dangling_raw_ptr.rs @@ -0,0 +1,10 @@ +#![feature(const_let)] + +const FOO: *const u32 = { //~ ERROR any use of this value will cause an error + let x = 42; + &x +}; + +fn main() { + let x = FOO; +} diff --git a/src/test/ui/consts/dangling_raw_ptr.stderr b/src/test/ui/consts/dangling_raw_ptr.stderr new file mode 100644 index 0000000000000..3b20936f8ae97 --- /dev/null +++ b/src/test/ui/consts/dangling_raw_ptr.stderr @@ -0,0 +1,13 @@ +error: any use of this value will cause an error + --> $DIR/dangling_raw_ptr.rs:3:1 + | +LL | / const FOO: *const u32 = { //~ ERROR any use of this value will cause an error +LL | | let x = 42; +LL | | &x +LL | | }; + | |__^ type validation failed: encountered dangling pointer in final constant + | + = note: #[deny(const_err)] on by default + +error: aborting due to previous error + diff --git a/src/test/ui/consts/single_variant_match_ice.rs b/src/test/ui/consts/single_variant_match_ice.rs new file mode 100644 index 0000000000000..67a41bc5dc4ad --- /dev/null +++ b/src/test/ui/consts/single_variant_match_ice.rs @@ -0,0 +1,15 @@ +enum Foo { + Prob, +} + +impl Foo { + pub const fn as_val(&self) -> u8 { + use self::Foo::*; + + match *self { + Prob => 0x1, //~ ERROR `if`, `match`, `&&` and `||` are not stable in const fn + } + } +} + +fn main() {} diff --git a/src/test/ui/consts/single_variant_match_ice.stderr b/src/test/ui/consts/single_variant_match_ice.stderr new file mode 100644 index 0000000000000..a0222b0d489a4 --- /dev/null +++ b/src/test/ui/consts/single_variant_match_ice.stderr @@ -0,0 +1,8 @@ +error: `if`, `match`, `&&` and `||` are not stable in const fn + --> $DIR/single_variant_match_ice.rs:10:13 + | +LL | Prob => 0x1, //~ ERROR `if`, `match`, `&&` and `||` are not stable in const fn + | ^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/feature-gates/feature-gate-lint-reasons.rs b/src/test/ui/feature-gates/feature-gate-lint-reasons.rs new file mode 100644 index 0000000000000..1a7b9c990fa64 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-lint-reasons.rs @@ -0,0 +1,4 @@ +#![warn(nonstandard_style, reason = "the standard should be respected")] +//~^ ERROR lint reasons are experimental + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-lint-reasons.stderr b/src/test/ui/feature-gates/feature-gate-lint-reasons.stderr new file mode 100644 index 0000000000000..6a36d9fd5a8e5 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-lint-reasons.stderr @@ -0,0 +1,11 @@ +error[E0658]: lint reasons are experimental (see issue #54503) + --> $DIR/feature-gate-lint-reasons.rs:1:28 + | +LL | #![warn(nonstandard_style, reason = "the standard should be respected")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(lint_reasons)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/lint/empty-lint-attributes.rs b/src/test/ui/lint/empty-lint-attributes.rs new file mode 100644 index 0000000000000..1f0a9538d88b1 --- /dev/null +++ b/src/test/ui/lint/empty-lint-attributes.rs @@ -0,0 +1,17 @@ +#![feature(lint_reasons)] + +// run-pass + +// Empty (and reason-only) lint attributes are legal—although we may want to +// lint them in the future (Issue #55112). + +#![allow()] +#![warn(reason = "observationalism")] + +#[forbid()] +fn devoir() {} + +#[deny(reason = "ultion")] +fn waldgrave() {} + +fn main() {} diff --git a/src/test/ui/lint/reasons-erroneous.rs b/src/test/ui/lint/reasons-erroneous.rs new file mode 100644 index 0000000000000..e42b329338b5a --- /dev/null +++ b/src/test/ui/lint/reasons-erroneous.rs @@ -0,0 +1,24 @@ +#![feature(lint_reasons)] + +#![warn(absolute_paths_not_starting_with_crate, reason = 0)] +//~^ ERROR malformed lint attribute +//~| HELP reason must be a string literal +#![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")] +//~^ ERROR malformed lint attribute +//~| HELP reason must be a string literal +#![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")] +//~^ ERROR malformed lint attribute +#![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")] +//~^ ERROR malformed lint attribute +#![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))] +//~^ ERROR malformed lint attribute +#![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")] +//~^ ERROR malformed lint attribute +//~| HELP reason in lint attribute must come last +#![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)] +//~^ ERROR malformed lint attribute +//~| HELP reason in lint attribute must come last +#![warn(missing_copy_implementations, reason)] +//~^ WARN unknown lint + +fn main() {} diff --git a/src/test/ui/lint/reasons-erroneous.stderr b/src/test/ui/lint/reasons-erroneous.stderr new file mode 100644 index 0000000000000..6842686ecbab5 --- /dev/null +++ b/src/test/ui/lint/reasons-erroneous.stderr @@ -0,0 +1,61 @@ +error[E0452]: malformed lint attribute + --> $DIR/reasons-erroneous.rs:3:58 + | +LL | #![warn(absolute_paths_not_starting_with_crate, reason = 0)] + | ^ + | + = help: reason must be a string literal + +error[E0452]: malformed lint attribute + --> $DIR/reasons-erroneous.rs:6:40 + | +LL | #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: reason must be a string literal + +error[E0452]: malformed lint attribute + --> $DIR/reasons-erroneous.rs:9:29 + | +LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0452]: malformed lint attribute + --> $DIR/reasons-erroneous.rs:11:23 + | +LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0452]: malformed lint attribute + --> $DIR/reasons-erroneous.rs:13:36 + | +LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0452]: malformed lint attribute + --> $DIR/reasons-erroneous.rs:15:44 + | +LL | #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: reason in lint attribute must come last + +error[E0452]: malformed lint attribute + --> $DIR/reasons-erroneous.rs:18:25 + | +LL | #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: reason in lint attribute must come last + +warning: unknown lint: `reason` + --> $DIR/reasons-erroneous.rs:21:39 + | +LL | #![warn(missing_copy_implementations, reason)] + | ^^^^^^ + | + = note: #[warn(unknown_lints)] on by default + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0452`. diff --git a/src/test/ui/lint/reasons-forbidden.rs b/src/test/ui/lint/reasons-forbidden.rs new file mode 100644 index 0000000000000..19ab76707d408 --- /dev/null +++ b/src/test/ui/lint/reasons-forbidden.rs @@ -0,0 +1,21 @@ +#![feature(lint_reasons)] + +#![forbid( + unsafe_code, + //~^ NOTE `forbid` level set here + reason = "our errors & omissions insurance policy doesn't cover unsafe Rust" +)] + +use std::ptr; + +fn main() { + let a_billion_dollar_mistake = ptr::null(); + + #[allow(unsafe_code)] + //~^ ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) + //~| NOTE overruled by previous forbid + //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust + unsafe { + *a_billion_dollar_mistake + } +} diff --git a/src/test/ui/lint/reasons-forbidden.stderr b/src/test/ui/lint/reasons-forbidden.stderr new file mode 100644 index 0000000000000..ea09e591cba0f --- /dev/null +++ b/src/test/ui/lint/reasons-forbidden.stderr @@ -0,0 +1,14 @@ +error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) + --> $DIR/reasons-forbidden.rs:14:13 + | +LL | unsafe_code, + | ----------- `forbid` level set here +... +LL | #[allow(unsafe_code)] + | ^^^^^^^^^^^ overruled by previous forbid + | + = note: our errors & omissions insurance policy doesn't cover unsafe Rust + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0453`. diff --git a/src/test/ui/lint/reasons.rs b/src/test/ui/lint/reasons.rs new file mode 100644 index 0000000000000..eba91d92afb5b --- /dev/null +++ b/src/test/ui/lint/reasons.rs @@ -0,0 +1,33 @@ +// compile-pass + +#![feature(lint_reasons)] + +#![warn(elided_lifetimes_in_paths, + //~^ NOTE lint level defined here + reason = "explicit anonymous lifetimes aid reasoning about ownership")] +#![warn( + nonstandard_style, + //~^ NOTE lint level defined here + reason = r#"people shouldn't have to change their usual style habits +to contribute to our project"# +)] +#![allow(unused, reason = "unused code has never killed anypony")] + +use std::fmt; + +pub struct CheaterDetectionMechanism {} + +impl fmt::Debug for CheaterDetectionMechanism { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + //~^ WARN hidden lifetime parameters in types are deprecated + //~| NOTE explicit anonymous lifetimes aid + //~| HELP indicate the anonymous lifetime + fmt.debug_struct("CheaterDetectionMechanism").finish() + } +} + +fn main() { + let Social_exchange_psychology = CheaterDetectionMechanism {}; + //~^ WARN should have a snake case name such as + //~| NOTE people shouldn't have to change their usual style habits +} diff --git a/src/test/ui/lint/reasons.stderr b/src/test/ui/lint/reasons.stderr new file mode 100644 index 0000000000000..df0f9cb9b61e8 --- /dev/null +++ b/src/test/ui/lint/reasons.stderr @@ -0,0 +1,28 @@ +warning: hidden lifetime parameters in types are deprecated + --> $DIR/reasons.rs:21:29 + | +LL | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + | ^^^^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>` + | + = note: explicit anonymous lifetimes aid reasoning about ownership +note: lint level defined here + --> $DIR/reasons.rs:5:9 + | +LL | #![warn(elided_lifetimes_in_paths, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: variable `Social_exchange_psychology` should have a snake case name such as `social_exchange_psychology` + --> $DIR/reasons.rs:30:9 + | +LL | let Social_exchange_psychology = CheaterDetectionMechanism {}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: people shouldn't have to change their usual style habits + to contribute to our project +note: lint level defined here + --> $DIR/reasons.rs:9:5 + | +LL | nonstandard_style, + | ^^^^^^^^^^^^^^^^^ + = note: #[warn(non_snake_case)] implied by #[warn(nonstandard_style)] + diff --git a/src/test/ui/rust-2018/local-path-suggestions-2018.stderr b/src/test/ui/rust-2018/local-path-suggestions-2018.stderr index 97bf748881f29..2293f4b001749 100644 --- a/src/test/ui/rust-2018/local-path-suggestions-2018.stderr +++ b/src/test/ui/rust-2018/local-path-suggestions-2018.stderr @@ -3,6 +3,8 @@ error[E0432]: unresolved import `foo` | LL | use foo::Bar; | ^^^ Did you mean `crate::foo`? + | + = note: `use` statements changed in Rust 2018; read more at error[E0432]: unresolved import `foo` --> $DIR/local-path-suggestions-2018.rs:27:5 diff --git a/src/test/ui/static/static-extern-type.rs b/src/test/ui/static/static-extern-type.rs new file mode 100644 index 0000000000000..72e2853b9f038 --- /dev/null +++ b/src/test/ui/static/static-extern-type.rs @@ -0,0 +1,37 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass +#![feature(extern_types)] + +pub mod a { + extern "C" { + pub type StartFn; + pub static start: StartFn; + } +} + +pub mod b { + #[repr(transparent)] + pub struct TransparentType(::a::StartFn); + extern "C" { + pub static start: TransparentType; + } +} + +pub mod c { + #[repr(C)] + pub struct CType(u32, ::b::TransparentType); + extern "C" { + pub static start: CType; + } +} + +fn main() {}