diff --git a/.travis.yml b/.travis.yml index b208e760d95c6..14fb17aeeddca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -227,9 +227,9 @@ install: chmod +x /usr/local/bin/sccache && travis_retry curl -fo /usr/local/bin/stamp https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2017-03-17-stamp-x86_64-apple-darwin && chmod +x /usr/local/bin/stamp && - travis_retry curl -f http://releases.llvm.org/6.0.0/clang+llvm-6.0.0-x86_64-apple-darwin.tar.xz | tar xJf - && - export CC=`pwd`/clang+llvm-6.0.0-x86_64-apple-darwin/bin/clang && - export CXX=`pwd`/clang+llvm-6.0.0-x86_64-apple-darwin/bin/clang++ && + travis_retry curl -f http://releases.llvm.org/7.0.0/clang+llvm-7.0.0-x86_64-apple-darwin.tar.xz | tar xJf - && + export CC=`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/bin/clang && + export CXX=`pwd`/clang+llvm-7.0.0-x86_64-apple-darwin/bin/clang++ && export AR=ar ;; esac diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index c8689f7814086..b6bb11d07ef04 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -22,7 +22,7 @@ use std::fs::{self, File}; use std::io::BufReader; use std::io::prelude::*; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; +use std::process::{Command, Stdio, exit}; use std::str; use build_helper::{output, mtime, up_to_date}; @@ -1098,7 +1098,7 @@ pub fn run_cargo(builder: &Builder, }); if !ok { - panic!("cargo must succeed"); + exit(1); } // Ok now we need to actually find all the files listed in `toplevel`. We've diff --git a/src/ci/docker/dist-i686-linux/Dockerfile b/src/ci/docker/dist-i686-linux/Dockerfile index 8df49f364a372..b087ea7899f4c 100644 --- a/src/ci/docker/dist-i686-linux/Dockerfile +++ b/src/ci/docker/dist-i686-linux/Dockerfile @@ -67,7 +67,7 @@ RUN ./build-gcc.sh COPY dist-x86_64-linux/build-python.sh /tmp/ RUN ./build-python.sh -# Now build LLVM+Clang 6, afterwards configuring further compilations to use the +# Now build LLVM+Clang 7, afterwards configuring further compilations to use the # clang/clang++ compilers. COPY dist-x86_64-linux/build-clang.sh /tmp/ RUN ./build-clang.sh diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile index 0a2dae72f7382..a1a778c2b2c61 100644 --- a/src/ci/docker/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/dist-x86_64-linux/Dockerfile @@ -67,7 +67,7 @@ RUN ./build-gcc.sh COPY dist-x86_64-linux/build-python.sh /tmp/ RUN ./build-python.sh -# Now build LLVM+Clang 6, afterwards configuring further compilations to use the +# Now build LLVM+Clang 7, afterwards configuring further compilations to use the # clang/clang++ compilers. COPY dist-x86_64-linux/build-clang.sh /tmp/ RUN ./build-clang.sh diff --git a/src/ci/docker/dist-x86_64-linux/build-clang.sh b/src/ci/docker/dist-x86_64-linux/build-clang.sh index 4595eacb31061..2762f0bf7ec74 100755 --- a/src/ci/docker/dist-x86_64-linux/build-clang.sh +++ b/src/ci/docker/dist-x86_64-linux/build-clang.sh @@ -13,7 +13,7 @@ set -ex source shared.sh -LLVM=6.0.0 +LLVM=7.0.0 mkdir clang cd clang diff --git a/src/ci/docker/scripts/musl.sh b/src/ci/docker/scripts/musl.sh index fcebfb932474c..11d85471b7c08 100644 --- a/src/ci/docker/scripts/musl.sh +++ b/src/ci/docker/scripts/musl.sh @@ -51,7 +51,7 @@ hide_output make clean cd .. -LLVM=60 +LLVM=70 # may have been downloaded in a previous run if [ ! -d libunwind-release_$LLVM ]; then diff --git a/src/librustc/cfg/graphviz.rs b/src/librustc/cfg/graphviz.rs index cc4f3f95d079a..650aa39114fad 100644 --- a/src/librustc/cfg/graphviz.rs +++ b/src/librustc/cfg/graphviz.rs @@ -106,8 +106,7 @@ impl<'a> dot::GraphWalk<'a> for &'a cfg::CFG { type Node = Node<'a>; type Edge = Edge<'a>; fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> { - let mut v = Vec::new(); - self.graph.each_node(|i, nd| { v.push((i, nd)); true }); + let v: Vec<_> = self.graph.enumerated_nodes().collect(); v.into() } fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index e532b50a28b6b..ce1e678043188 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1062,8 +1062,7 @@ impl<'a> LoweringContext<'a> { attrs .iter() .map(|a| self.lower_attr(a)) - .collect::>() - .into() + .collect() } fn lower_attr(&mut self, attr: &Attribute) -> Attribute { diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index f3a62975dd9f4..9001cef906f49 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -216,7 +216,9 @@ impl<'gcx> HashStable> for ty::adjustment::AutoBorrow } } -impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id }); +impl_stable_hash_for!(struct ty::UpvarPath { hir_id }); + +impl_stable_hash_for!(struct ty::UpvarId { var_path, closure_expr_id }); impl_stable_hash_for!(enum ty::BorrowKind { ImmBorrow, @@ -451,7 +453,7 @@ impl_stable_hash_for!( FunctionRetMismatch(a, b), NoMirFor(s), UnterminatedCString(ptr), - PointerOutOfBounds { ptr, access, allocation_size }, + PointerOutOfBounds { ptr, check, allocation_size }, InvalidBoolOp(bop), Unimplemented(s), BoundsCheck { len, index }, @@ -471,6 +473,11 @@ impl_stable_hash_for!( } ); +impl_stable_hash_for!(enum mir::interpret::InboundsCheck { + Live, + MaybeDead +}); + impl_stable_hash_for!(enum mir::interpret::Lock { NoLock, WriteLock(dl), @@ -673,9 +680,13 @@ for ty::TyKind<'gcx> Param(param_ty) => { param_ty.hash_stable(hcx, hasher); } - Bound(bound_ty) => { + Bound(debruijn, bound_ty) => { + debruijn.hash_stable(hcx, hasher); bound_ty.hash_stable(hcx, hasher); } + ty::Placeholder(placeholder_ty) => { + placeholder_ty.hash_stable(hcx, hasher); + } Foreign(def_id) => { def_id.hash_stable(hcx, hasher); } @@ -1085,12 +1096,13 @@ impl_stable_hash_for!(struct infer::canonical::CanonicalVarInfo { impl_stable_hash_for!(enum infer::canonical::CanonicalVarKind { Ty(k), + PlaceholderTy(placeholder), Region(ui), PlaceholderRegion(placeholder), }); impl_stable_hash_for!(enum infer::canonical::CanonicalTyVarKind { - General, + General(ui), Int, Float }); diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index a787eeae663fd..ddb520775da0a 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, BoundVar, Lift, List, Ty, TyCtxt, TypeFlags}; +use ty::{self, BoundVar, Lift, List, Ty, TyCtxt, TypeFlags}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; @@ -339,11 +339,35 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match t.sty { - ty::Infer(ty::TyVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::General, t), + ty::Infer(ty::TyVar(vid)) => { + match self.infcx.unwrap().probe_ty_var(vid) { + // `t` could be a float / int variable: canonicalize that instead + Ok(t) => self.fold_ty(t), + + // `TyVar(vid)` is unresolved, track its universe index in the canonicalized + // result + Err(ui) => self.canonicalize_ty_var( + CanonicalVarInfo { + kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) + }, + t + ) + } + } - ty::Infer(ty::IntVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::Int, t), + ty::Infer(ty::IntVar(_)) => self.canonicalize_ty_var( + CanonicalVarInfo { + kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) + }, + t + ), - ty::Infer(ty::FloatVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::Float, t), + ty::Infer(ty::FloatVar(_)) => self.canonicalize_ty_var( + CanonicalVarInfo { + kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) + }, + t + ), ty::Infer(ty::FreshTy(_)) | ty::Infer(ty::FreshIntTy(_)) @@ -351,8 +375,15 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> bug!("encountered a fresh type during canonicalization") } - ty::Bound(bound_ty) => { - if bound_ty.index >= self.binder_index { + ty::Placeholder(placeholder) => self.canonicalize_ty_var( + CanonicalVarInfo { + kind: CanonicalVarKind::PlaceholderTy(placeholder) + }, + t + ), + + ty::Bound(debruijn, _) => { + if debruijn >= self.binder_index { bug!("escaping bound type during canonicalization") } else { t @@ -408,9 +439,13 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { V: TypeFoldable<'tcx> + Lift<'gcx>, { let needs_canonical_flags = if canonicalize_region_mode.any() { - TypeFlags::HAS_FREE_REGIONS | TypeFlags::KEEP_IN_LOCAL_TCX + TypeFlags::KEEP_IN_LOCAL_TCX | + TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS` + TypeFlags::HAS_TY_PLACEHOLDER } else { - TypeFlags::KEEP_IN_LOCAL_TCX + TypeFlags::KEEP_IN_LOCAL_TCX | + TypeFlags::HAS_RE_PLACEHOLDER | + TypeFlags::HAS_TY_PLACEHOLDER }; let gcx = tcx.global_tcx(); @@ -574,17 +609,14 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { /// if `ty_var` is bound to anything; if so, canonicalize /// *that*. Otherwise, create a new canonical variable for /// `ty_var`. - fn canonicalize_ty_var(&mut self, ty_kind: CanonicalTyVarKind, ty_var: Ty<'tcx>) -> Ty<'tcx> { + fn canonicalize_ty_var(&mut self, info: CanonicalVarInfo, ty_var: Ty<'tcx>) -> Ty<'tcx> { let infcx = self.infcx.expect("encountered ty-var without infcx"); let bound_to = infcx.shallow_resolve(ty_var); if bound_to != ty_var { self.fold_ty(bound_to) } else { - let info = CanonicalVarInfo { - kind: CanonicalVarKind::Ty(ty_kind), - }; let var = self.canonical_var(info, ty_var.into()); - self.tcx().mk_ty(ty::Bound(BoundTy::new(self.binder_index, var))) + self.tcx().mk_ty(ty::Bound(self.binder_index, var.into())) } } } diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs index f7eb7118f412f..230f8958b3385 100644 --- a/src/librustc/infer/canonical/mod.rs +++ b/src/librustc/infer/canonical/mod.rs @@ -122,6 +122,7 @@ impl CanonicalVarInfo { pub fn is_existential(&self) -> bool { match self.kind { CanonicalVarKind::Ty(_) => true, + CanonicalVarKind::PlaceholderTy(_) => false, CanonicalVarKind::Region(_) => true, CanonicalVarKind::PlaceholderRegion(..) => false, } @@ -136,24 +137,27 @@ pub enum CanonicalVarKind { /// Some kind of type inference variable. Ty(CanonicalTyVarKind), + /// A "placeholder" that represents "any type". + PlaceholderTy(ty::PlaceholderType), + /// Region variable `'?R`. Region(ty::UniverseIndex), /// A "placeholder" that represents "any region". Created when you /// are solving a goal like `for<'a> T: Foo<'a>` to represent the /// bound region `'a`. - PlaceholderRegion(ty::Placeholder), + PlaceholderRegion(ty::PlaceholderRegion), } impl CanonicalVarKind { pub fn universe(self) -> ty::UniverseIndex { match self { - // At present, we don't support higher-ranked - // quantification over types, so all type variables are in - // the root universe. - CanonicalVarKind::Ty(_) => ty::UniverseIndex::ROOT, + CanonicalVarKind::Ty(kind) => match kind { + CanonicalTyVarKind::General(ui) => ui, + CanonicalTyVarKind::Float | CanonicalTyVarKind::Int => ty::UniverseIndex::ROOT, + } - // Region variables can be created in sub-universes. + CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe, CanonicalVarKind::Region(ui) => ui, CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe, } @@ -168,7 +172,7 @@ impl CanonicalVarKind { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] pub enum CanonicalTyVarKind { /// General type variable `?T` that can be unified with arbitrary types. - General, + General(ty::UniverseIndex), /// Integral type variable `?I` (that can only be unified with integral types). Int, @@ -358,8 +362,11 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { match cv_info.kind { CanonicalVarKind::Ty(ty_kind) => { let ty = match ty_kind { - CanonicalTyVarKind::General => { - self.next_ty_var(TypeVariableOrigin::MiscVariable(span)) + CanonicalTyVarKind::General(ui) => { + self.next_ty_var_in_universe( + TypeVariableOrigin::MiscVariable(span), + universe_map(ui) + ) } CanonicalTyVarKind::Int => self.tcx.mk_int_var(self.next_int_var_id()), @@ -369,20 +376,27 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { ty.into() } + CanonicalVarKind::PlaceholderTy(ty::PlaceholderType { universe, name }) => { + let universe_mapped = universe_map(universe); + let placeholder_mapped = ty::PlaceholderType { + universe: universe_mapped, + name, + }; + self.tcx.mk_ty(ty::Placeholder(placeholder_mapped)).into() + } + CanonicalVarKind::Region(ui) => self.next_region_var_in_universe( RegionVariableOrigin::MiscVariable(span), universe_map(ui), ).into(), - CanonicalVarKind::PlaceholderRegion(ty::Placeholder { universe, name }) => { + CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion { universe, name }) => { let universe_mapped = universe_map(universe); - let placeholder_mapped = ty::Placeholder { + let placeholder_mapped = ty::PlaceholderRegion { universe: universe_mapped, name, }; - self.tcx - .mk_region(ty::RePlaceholder(placeholder_mapped)) - .into() + self.tcx.mk_region(ty::RePlaceholder(placeholder_mapped)).into() } } } diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs index 6f3d10268351a..d32594ebdf366 100644 --- a/src/librustc/infer/canonical/query_response.rs +++ b/src/librustc/infer/canonical/query_response.rs @@ -435,21 +435,21 @@ 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::Bound(b) = result_value.sty { + if let ty::Bound(debruijn, 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); + assert_eq!(debruijn, 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::ReLateBound(index, br) = result_value { + if let &ty::RegionKind::ReLateBound(debruijn, 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); + assert_eq!(debruijn, ty::INNERMOST); opt_values[br.assert_bound_var()] = Some(*original_value); } } diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index f833ebc7ca763..59a490f4a013d 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1315,7 +1315,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { format!(" for lifetime parameter `{}` in coherence check", name) } infer::UpvarRegion(ref upvar_id, _) => { - let var_node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_id); + let var_node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_path.hir_id); let var_name = self.tcx.hir.name(var_node_id); format!(" for capture of `{}` by closure", var_name) } diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs index 54d01a035a8be..a539c321af3f0 100644 --- a/src/librustc/infer/error_reporting/note.rs +++ b/src/librustc/infer/error_reporting/note.rs @@ -41,7 +41,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { "...so that reference does not outlive borrowed content"); } infer::ReborrowUpvar(span, ref upvar_id) => { - let var_node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_id); + let var_node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_path.hir_id); let var_name = self.tcx.hir.name(var_node_id); err.span_note(span, &format!("...so that closure can access `{}`", var_name)); @@ -174,7 +174,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err } infer::ReborrowUpvar(span, ref upvar_id) => { - let var_node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_id); + let var_node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_path.hir_id); let var_name = self.tcx.hir.name(var_node_id); let mut err = struct_span_err!(self.tcx.sess, span, diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index b53444992fa21..d17cf0c7b47a4 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -170,9 +170,6 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { t } - ty::Bound(..) => - bug!("encountered bound ty during freshening"), - ty::Generator(..) | ty::Bool | ty::Char | @@ -200,6 +197,9 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::Opaque(..) => { t.super_fold_with(self) } + + ty::Placeholder(..) | + ty::Bound(..) => bug!("unexpected type {:?}", t), } } } diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 8172f620c3646..5218aa36facc1 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -53,7 +53,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // First, we instantiate each bound region in the supertype with a // fresh placeholder region. let (b_prime, placeholder_map) = - self.infcx.replace_late_bound_regions_with_placeholders(b); + self.infcx.replace_bound_vars_with_placeholders(b); // Next, we instantiate each bound region in the subtype // with a fresh region variable. These region variables -- @@ -115,7 +115,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // First, we instantiate each bound region in the matcher // with a placeholder region. let ((a_match, a_value), placeholder_map) = - self.infcx.replace_late_bound_regions_with_placeholders(a_pair); + self.infcx.replace_bound_vars_with_placeholders(a_pair); debug!("higher_ranked_match: a_match={:?}", a_match); debug!("higher_ranked_match: placeholder_map={:?}", placeholder_map); @@ -314,10 +314,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { region_vars } - /// Replace all regions bound by `binder` with placeholder regions and - /// return a map indicating which bound-region was replaced with what - /// placeholder region. This is the first step of checking subtyping - /// when higher-ranked things are involved. + /// Replace all regions (resp. types) bound by `binder` with placeholder + /// regions (resp. types) and return a map indicating which bound-region + /// was replaced with what placeholder region. This is the first step of + /// checking subtyping when higher-ranked things are involved. /// /// **Important:** you must call this function from within a snapshot. /// Moreover, before committing the snapshot, you must eventually call @@ -330,26 +330,37 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// the [rustc guide]. /// /// [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/traits/hrtb.html - pub fn replace_late_bound_regions_with_placeholders( + pub fn replace_bound_vars_with_placeholders( &self, - binder: &ty::Binder, + binder: &ty::Binder ) -> (T, PlaceholderMap<'tcx>) where - T : TypeFoldable<'tcx>, + T: TypeFoldable<'tcx> { let next_universe = self.create_next_universe(); - let (result, map) = self.tcx.replace_late_bound_regions(binder, |br| { - self.tcx.mk_region(ty::RePlaceholder(ty::Placeholder { + let fld_r = |br| { + self.tcx.mk_region(ty::RePlaceholder(ty::PlaceholderRegion { universe: next_universe, name: br, })) - }); + }; + + let fld_t = |bound_ty: ty::BoundTy| { + self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType { + universe: next_universe, + name: bound_ty.var, + })) + }; + + let (result, map) = self.tcx.replace_bound_vars(binder, fld_r, fld_t); - debug!("replace_late_bound_regions_with_placeholders(binder={:?}, result={:?}, map={:?})", - binder, - result, - map); + debug!( + "replace_bound_vars_with_placeholders(binder={:?}, result={:?}, map={:?})", + binder, + result, + map + ); (result, map) } @@ -530,7 +541,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// Pops the placeholder regions found in `placeholder_map` from the region /// inference context. Whenever you create placeholder regions via - /// `replace_late_bound_regions_with_placeholders`, they must be popped before you + /// `replace_bound_vars_with_placeholders`, they must be popped before you /// commit the enclosing snapshot (if you do not commit, e.g. within a /// probe or as a result of an error, then this is not necessary, as /// popping happens as part of the rollback). diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 87e32be1a1759..a29c85bd2b1c5 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -227,7 +227,7 @@ pub struct InferCtxt<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { universe: Cell, } -/// A map returned by `replace_late_bound_regions_with_placeholders()` +/// A map returned by `replace_bound_vars_with_placeholders()` /// indicating the placeholder region that each late-bound region was /// replaced with. pub type PlaceholderMap<'tcx> = BTreeMap>; @@ -411,7 +411,7 @@ pub enum NLLRegionVariableOrigin { /// "Universal" instantiation of a higher-ranked region (e.g., /// from a `for<'a> T` binder). Meant to represent "any region". - Placeholder(ty::Placeholder), + Placeholder(ty::PlaceholderRegion), Existential, } @@ -935,7 +935,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { b, }, placeholder_map, - ) = self.replace_late_bound_regions_with_placeholders(predicate); + ) = self.replace_bound_vars_with_placeholders(predicate); let cause_span = cause.span; let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?; @@ -952,7 +952,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ) -> UnitResult<'tcx> { self.commit_if_ok(|snapshot| { let (ty::OutlivesPredicate(r_a, r_b), placeholder_map) = - self.replace_late_bound_regions_with_placeholders(predicate); + self.replace_bound_vars_with_placeholders(predicate); let origin = SubregionOrigin::from_obligation_cause(cause, || { RelateRegionParamBound(cause.span) }); @@ -972,6 +972,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.mk_var(self.next_ty_var_id(false, origin)) } + pub fn next_ty_var_in_universe( + &self, + origin: TypeVariableOrigin, + universe: ty::UniverseIndex + ) -> Ty<'tcx> { + let vid = self.type_variables + .borrow_mut() + .new_var(universe, false, origin); + self.tcx.mk_var(vid) + } + pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { self.tcx.mk_var(self.next_ty_var_id(true, origin)) } @@ -1227,6 +1238,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } + /// If `TyVar(vid)` resolves to a type, return that type. Else, return the + /// universe index of `TyVar(vid)`. + pub fn probe_ty_var(&self, vid: TyVid) -> Result, ty::UniverseIndex> { + use self::type_variable::TypeVariableValue; + + match self.type_variables.borrow_mut().probe(vid) { + TypeVariableValue::Known { value } => Ok(value), + TypeVariableValue::Unknown { universe } => Err(universe), + } + } + pub fn shallow_resolve(&self, typ: Ty<'tcx>) -> Ty<'tcx> { self.inlined_shallow_resolve(typ) } diff --git a/src/librustc/infer/nll_relate/mod.rs b/src/librustc/infer/nll_relate/mod.rs index e003c1989e096..9bdbf77fee0a9 100644 --- a/src/librustc/infer/nll_relate/mod.rs +++ b/src/librustc/infer/nll_relate/mod.rs @@ -95,7 +95,7 @@ pub trait TypeRelatingDelegate<'tcx> { /// So e.g. if you have `for<'a> fn(..) <: for<'b> fn(..)`, then /// we will invoke this method to instantiate `'b` with a /// placeholder region. - fn next_placeholder_region(&mut self, placeholder: ty::Placeholder) -> ty::Region<'tcx>; + fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx>; /// Creates a new existential region in the given universe. This /// is used when handling subtyping and type variables -- if we @@ -176,7 +176,7 @@ where universe }); - let placeholder = ty::Placeholder { universe, name: br }; + let placeholder = ty::PlaceholderRegion { universe, name: br }; delegate.next_placeholder_region(placeholder) } else { delegate.next_existential_region_var() diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index bec19ba9099dc..5624961ea6e67 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -72,7 +72,7 @@ pub type TypeVariableMap = FxHashMap; struct TypeVariableData { origin: TypeVariableOrigin, - diverging: bool + diverging: bool, } #[derive(Copy, Clone, Debug)] diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 7e9b26bbf729c..5b92bfe6ad3c4 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -938,7 +938,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { let var_hir_id = self.tcx().hir.node_to_hir_id(freevar.var_id()); let closure_def_id = self.tcx().hir.local_def_id(closure_expr.id); let upvar_id = ty::UpvarId { - var_id: var_hir_id, + var_path: ty::UpvarPath { hir_id: var_hir_id }, closure_expr_id: closure_def_id.to_local(), }; let upvar_capture = self.mc.tables.upvar_capture(upvar_id); diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 59ef8fa14484b..cadf0c42d228f 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -818,7 +818,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let closure_expr_def_id = self.tcx.hir.local_def_id(fn_node_id); let var_hir_id = self.tcx.hir.node_to_hir_id(var_id); let upvar_id = ty::UpvarId { - var_id: var_hir_id, + var_path: ty::UpvarPath { hir_id: var_hir_id }, closure_expr_id: closure_expr_def_id.to_local(), }; diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs index cc92b63256c1f..02c0ebcec4fef 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -19,6 +19,14 @@ use mir; use std::ops::{Deref, DerefMut}; use rustc_data_structures::sorted_map::SortedMap; +/// Used by `check_bounds` to indicate whether the pointer needs to be just inbounds +/// or also inbounds of a *live* allocation. +#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable)] +pub enum InboundsCheck { + Live, + MaybeDead, +} + #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct Allocation { /// The actual bytes of the allocation. diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index f28aa41ed4222..bf678db51c952 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -15,7 +15,7 @@ use ty::{Ty, layout}; use ty::layout::{Size, Align, LayoutError}; use rustc_target::spec::abi::Abi; -use super::{Pointer, Scalar}; +use super::{Pointer, InboundsCheck, ScalarMaybeUndef}; use backtrace::Backtrace; @@ -240,10 +240,10 @@ pub enum EvalErrorKind<'tcx, O> { InvalidMemoryAccess, InvalidFunctionPointer, InvalidBool, - InvalidDiscriminant(Scalar), + InvalidDiscriminant(ScalarMaybeUndef), PointerOutOfBounds { ptr: Pointer, - access: bool, + check: InboundsCheck, allocation_size: Size, }, InvalidNullPointerUsage, @@ -457,9 +457,13 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use self::EvalErrorKind::*; match *self { - PointerOutOfBounds { ptr, access, allocation_size } => { - write!(f, "{} at offset {}, outside bounds of allocation {} which has size {}", - if access { "memory access" } else { "pointer computed" }, + PointerOutOfBounds { ptr, check, allocation_size } => { + write!(f, "Pointer must be in-bounds{} at offset {}, but is outside bounds of \ + allocation {} which has size {}", + match check { + InboundsCheck::Live => " and live", + InboundsCheck::MaybeDead => "", + }, ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes()) }, ValidationFailure(ref err) => { diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 40daf78f546fb..ec25431bd1ffe 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -28,7 +28,7 @@ pub use self::error::{ pub use self::value::{Scalar, ConstValue, ScalarMaybeUndef}; pub use self::allocation::{ - Allocation, AllocationExtra, + InboundsCheck, Allocation, AllocationExtra, Relocations, UndefMask, }; diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 71b77909b82a8..b7a84c99308f8 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::Bound(..) | ty::Infer(..) => match in_crate { + ty::Placeholder(..) | 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 2761a954cea88..d757cb220c6ac 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::Bound(..) | ty::Infer(..) | ty::Error => None, + ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error => None, ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), } } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index b59bd0e238873..e7b5fc3d1ffd7 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -204,7 +204,7 @@ pub fn poly_project_and_unify_type<'cx, 'gcx, 'tcx>( let infcx = selcx.infcx(); infcx.commit_if_ok(|snapshot| { let (placeholder_predicate, placeholder_map) = - infcx.replace_late_bound_regions_with_placeholders(&obligation.predicate); + infcx.replace_bound_vars_with_placeholders(&obligation.predicate); let skol_obligation = obligation.with(placeholder_predicate); let r = match project_and_unify_type(selcx, &skol_obligation) { @@ -424,7 +424,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, if let ConstValue::Unevaluated(def_id, substs) = constant.val { let tcx = self.selcx.tcx().global_tcx(); if let Some(param_env) = self.tcx().lift_to_global(&self.param_env) { - if substs.needs_infer() || substs.has_skol() { + if substs.needs_infer() || substs.has_placeholders() { let identity_substs = Substs::identity_for_item(tcx, def_id); let instance = ty::Instance::resolve(tcx, param_env, def_id, identity_substs); if let Some(instance) = instance { @@ -1656,7 +1656,7 @@ impl<'tcx> ProjectionCache<'tcx> { } pub fn rollback_placeholder(&mut self, snapshot: &ProjectionCacheSnapshot) { - self.map.partial_rollback(&snapshot.snapshot, &|k| k.ty.has_re_skol()); + self.map.partial_rollback(&snapshot.snapshot, &|k| k.ty.has_re_placeholders()); } pub fn commit(&mut self, snapshot: &ProjectionCacheSnapshot) { diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs index 99dc099d57738..b8bf0fcc15307 100644 --- a/src/librustc/traits/query/dropck_outlives.rs +++ b/src/librustc/traits/query/dropck_outlives.rs @@ -251,6 +251,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> | ty::Projection(..) | ty::Param(_) | ty::Opaque(..) + | ty::Placeholder(..) | ty::Infer(_) | ty::Bound(..) | ty::Generator(..) => false, diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs index 59b086e35de31..91b2ba301c312 100644 --- a/src/librustc/traits/query/normalize.rs +++ b/src/librustc/traits/query/normalize.rs @@ -202,7 +202,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx if let ConstValue::Unevaluated(def_id, substs) = constant.val { let tcx = self.infcx.tcx.global_tcx(); if let Some(param_env) = self.tcx().lift_to_global(&self.param_env) { - if substs.needs_infer() || substs.has_skol() { + if substs.needs_infer() || substs.has_placeholders() { let identity_substs = Substs::identity_for_item(tcx, def_id); let instance = ty::Instance::resolve(tcx, param_env, def_id, identity_substs); if let Some(instance) = instance { diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 550c27ca0ab8b..0f59f478cb415 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1726,7 +1726,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let poly_trait_predicate = self.infcx() .resolve_type_vars_if_possible(&obligation.predicate); let (skol_trait_predicate, placeholder_map) = self.infcx() - .replace_late_bound_regions_with_placeholders(&poly_trait_predicate); + .replace_bound_vars_with_placeholders(&poly_trait_predicate); debug!( "match_projection_obligation_against_definition_bounds: \ skol_trait_predicate={:?} placeholder_map={:?}", @@ -2470,7 +2470,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::Infer(ty::TyVar(_)) => Ambiguous, ty::UnnormalizedProjection(..) - | ty::Bound(_) + | ty::Placeholder(..) + | ty::Bound(..) | ty::Infer(ty::FreshTy(_)) | ty::Infer(ty::FreshIntTy(_)) | ty::Infer(ty::FreshFloatTy(_)) => { @@ -2555,7 +2556,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } ty::UnnormalizedProjection(..) - | ty::Bound(_) + | ty::Placeholder(..) + | ty::Bound(..) | ty::Infer(ty::FreshTy(_)) | ty::Infer(ty::FreshIntTy(_)) | ty::Infer(ty::FreshFloatTy(_)) => { @@ -2594,11 +2596,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { | ty::Char => Vec::new(), ty::UnnormalizedProjection(..) + | ty::Placeholder(..) | ty::Dynamic(..) | ty::Param(..) | ty::Foreign(..) | ty::Projection(..) - | ty::Bound(_) + | ty::Bound(..) | ty::Infer(ty::TyVar(_)) | ty::Infer(ty::FreshTy(_)) | ty::Infer(ty::FreshIntTy(_)) @@ -2682,7 +2685,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.in_snapshot(|this, snapshot| { let (skol_ty, placeholder_map) = this.infcx() - .replace_late_bound_regions_with_placeholders(&ty); + .replace_bound_vars_with_placeholders(&ty); let Normalized { value: normalized_ty, mut obligations, @@ -2916,7 +2919,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let trait_obligations: Vec> = self.in_snapshot(|this, snapshot| { let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); let (trait_ref, placeholder_map) = this.infcx() - .replace_late_bound_regions_with_placeholders(&poly_trait_ref); + .replace_bound_vars_with_placeholders(&poly_trait_ref); let cause = obligation.derived_cause(ImplDerivedObligation); this.impl_or_trait_obligations( cause, @@ -3119,7 +3122,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.in_snapshot(|this, snapshot| { let (predicate, placeholder_map) = this.infcx() - .replace_late_bound_regions_with_placeholders(&obligation.predicate); + .replace_bound_vars_with_placeholders(&obligation.predicate); let trait_ref = predicate.trait_ref; let trait_def_id = trait_ref.def_id; let substs = trait_ref.substs; @@ -3582,7 +3585,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } let (skol_obligation, placeholder_map) = self.infcx() - .replace_late_bound_regions_with_placeholders(&obligation.predicate); + .replace_bound_vars_with_placeholders(&obligation.predicate); let skol_obligation_trait_ref = skol_obligation.trait_ref; let impl_substs = self.infcx diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 3e417f10c4494..36538ac0889de 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -324,7 +324,7 @@ impl<'tcx> TypeVisitor<'tcx> for BoundNamesCollector { use syntax::symbol::Symbol; match t.sty { - ty::Bound(bound_ty) if bound_ty.index == self.binder_index => { + ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { self.types.insert( bound_ty.var.as_u32(), match bound_ty.kind { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index cdfe8f53b854b..7503298bd6717 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -789,7 +789,7 @@ impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { pat_adjustments.hash_stable(hcx, hasher); hash_stable_hashmap(hcx, hasher, upvar_capture_map, |up_var_id, hcx| { let ty::UpvarId { - var_id, + var_path, closure_expr_id } = *up_var_id; @@ -798,14 +798,14 @@ impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { let var_owner_def_id = DefId { krate: local_id_root.krate, - index: var_id.owner, + index: var_path.hir_id.owner, }; let closure_def_id = DefId { krate: local_id_root.krate, index: closure_expr_id.to_def_id().index, }; (hcx.def_path_hash(var_owner_def_id), - var_id.local_id, + var_path.hir_id.local_id, hcx.def_path_hash(closure_def_id)) }); @@ -2250,7 +2250,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { pub fn print_debug_stats(self) { sty_debug_print!( self, - Adt, Array, Slice, RawPtr, Ref, FnDef, FnPtr, + Adt, Array, Slice, RawPtr, Ref, FnDef, FnPtr, Placeholder, Generator, GeneratorWitness, Dynamic, Closure, Tuple, Bound, Param, Infer, UnnormalizedProjection, Projection, Opaque, Foreign); diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 4737c72b1ef0f..90022a770c114 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -212,7 +212,8 @@ 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::Bound(_) | + ty::Placeholder(..) => "placeholder type".into(), + ty::Bound(..) => "bound type".into(), 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 380f95993f8fb..8304e36381572 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::Bound(..) | ty::Infer(_) | ty::Error => None, + ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) | ty::Error => None, } } diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 0764f363250dd..1ea7e27c0dcdb 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -115,8 +115,12 @@ impl FlagComputation { self.add_substs(&substs.substs); } - &ty::Bound(bound_ty) => { - self.add_binder(bound_ty.index); + &ty::Bound(debruijn, _) => { + self.add_binder(debruijn); + } + + &ty::Placeholder(..) => { + self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER); } &ty::Infer(infer) => { diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 2c7814831450c..6f0e8d4f02680 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -102,14 +102,14 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn needs_infer(&self) -> bool { self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER) } - fn has_skol(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_RE_SKOL) + fn has_placeholders(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_RE_PLACEHOLDER | TypeFlags::HAS_TY_PLACEHOLDER) } fn needs_subst(&self) -> bool { self.has_type_flags(TypeFlags::NEEDS_SUBST) } - fn has_re_skol(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_RE_SKOL) + fn has_re_placeholders(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_RE_PLACEHOLDER) } fn has_closure_types(&self) -> bool { self.has_type_flags(TypeFlags::HAS_TY_CLOSURE) @@ -460,8 +460,8 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for BoundVarReplacer<'a, 'gcx, 'tcx> fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match t.sty { - ty::Bound(bound_ty) => { - if bound_ty.index == self.current_index { + ty::Bound(debruijn, bound_ty) => { + if debruijn == self.current_index { let fld_t = &mut self.fld_t; let ty = fld_t(bound_ty); ty::fold::shift_vars( @@ -526,7 +526,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { T: TypeFoldable<'tcx> { // identity for bound types - let fld_t = |bound_ty| self.mk_ty(ty::Bound(bound_ty)); + let fld_t = |bound_ty| self.mk_ty(ty::Bound(ty::INNERMOST, bound_ty)); self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t) } @@ -722,16 +722,13 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Shifter<'a, 'gcx, 'tcx> { 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::Bound(debruijn, bound_ty) => { + if self.amount == 0 || debruijn < 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)) + self.tcx.mk_ty( + ty::Bound(debruijn.shifted_in(self.amount), bound_ty) + ) } } diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index d44ba03084159..f6c90ab0a1ad2 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -515,6 +515,7 @@ pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option { ty::Str | ty::FnPtr(_) | ty::Projection(_) | + ty::Placeholder(..) | ty::UnnormalizedProjection(..) | ty::Param(_) | ty::Opaque(..) | diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 79324bd97a3db..8f665d135f5d3 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -697,7 +697,9 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { Align::from_bytes(repr_align, repr_align).unwrap()); } + let optimize = !def.repr.inhibit_union_abi_opt(); let mut size = Size::ZERO; + let mut abi = Abi::Aggregate { sized: true }; let index = VariantIdx::new(0); for field in &variants[index] { assert!(!field.is_unsized()); @@ -708,13 +710,44 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } else { align = align.max(field.align); } + + // If all non-ZST fields have the same ABI, forward this ABI + if optimize && !field.is_zst() { + // Normalize scalar_unit to the maximal valid range + let field_abi = match &field.abi { + Abi::Scalar(x) => Abi::Scalar(scalar_unit(x.value)), + Abi::ScalarPair(x, y) => { + Abi::ScalarPair( + scalar_unit(x.value), + scalar_unit(y.value), + ) + } + Abi::Vector { element: x, count } => { + Abi::Vector { + element: scalar_unit(x.value), + count: *count, + } + } + Abi::Uninhabited | + Abi::Aggregate { .. } => Abi::Aggregate { sized: true }, + }; + + if size == Size::ZERO { + // first non ZST: initialize 'abi' + abi = field_abi; + } else if abi != field_abi { + // different fields have different ABI: reset to Aggregate + abi = Abi::Aggregate { sized: true }; + } + } + size = cmp::max(size, field.size); } return Ok(tcx.intern_layout(LayoutDetails { variants: Variants::Single { index }, fields: FieldPlacement::Union(variants[index].len()), - abi: Abi::Aggregate { sized: true }, + abi, align, size: size.abi_align(align) })); @@ -1133,6 +1166,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } ty::Bound(..) | + ty::Placeholder(..) | ty::UnnormalizedProjection(..) | ty::GeneratorWitness(..) | ty::Infer(_) => { @@ -1717,7 +1751,8 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> } ty::Projection(_) | ty::UnnormalizedProjection(..) | ty::Bound(..) | - ty::Opaque(..) | ty::Param(_) | ty::Infer(_) | ty::Error => { + ty::Placeholder(..) | 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 96f4b1ef8e32a..075e87ef0b2d5 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -49,7 +49,6 @@ use std::hash::{Hash, Hasher}; use std::ops::Deref; use rustc_data_structures::sync::{self, Lrc, ParallelIterator, par_iter}; use std::slice; -use std::vec::IntoIter; use std::{mem, ptr}; use syntax::ast::{self, DUMMY_NODE_ID, Name, Ident, NodeId}; use syntax::attr; @@ -433,7 +432,7 @@ bitflags! { const HAS_SELF = 1 << 1; const HAS_TY_INFER = 1 << 2; const HAS_RE_INFER = 1 << 3; - const HAS_RE_SKOL = 1 << 4; + const HAS_RE_PLACEHOLDER = 1 << 4; /// Does this have any `ReEarlyBound` regions? Used to /// determine whether substitition is required, since those @@ -468,6 +467,8 @@ bitflags! { /// if a global bound is safe to evaluate. const HAS_RE_LATE_BOUND = 1 << 13; + const HAS_TY_PLACEHOLDER = 1 << 14; + const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits | TypeFlags::HAS_SELF.bits | TypeFlags::HAS_RE_EARLY_BOUND.bits; @@ -479,7 +480,7 @@ bitflags! { TypeFlags::HAS_SELF.bits | TypeFlags::HAS_TY_INFER.bits | TypeFlags::HAS_RE_INFER.bits | - TypeFlags::HAS_RE_SKOL.bits | + TypeFlags::HAS_RE_PLACEHOLDER.bits | TypeFlags::HAS_RE_EARLY_BOUND.bits | TypeFlags::HAS_FREE_REGIONS.bits | TypeFlags::HAS_TY_ERR.bits | @@ -487,7 +488,8 @@ bitflags! { TypeFlags::HAS_TY_CLOSURE.bits | TypeFlags::HAS_FREE_LOCAL_NAMES.bits | TypeFlags::KEEP_IN_LOCAL_TCX.bits | - TypeFlags::HAS_RE_LATE_BOUND.bits; + TypeFlags::HAS_RE_LATE_BOUND.bits | + TypeFlags::HAS_TY_PLACEHOLDER.bits; } } @@ -731,12 +733,17 @@ impl List { } } +#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub struct UpvarPath { + pub hir_id: hir::HirId, +} + /// Upvars do not get their own node-id. Instead, we use the pair of /// the original var id (that is, the root variable that is referenced /// by the upvar) and the id of the closure expression. #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct UpvarId { - pub var_id: hir::HirId, + pub var_path: UpvarPath, pub closure_expr_id: LocalDefId, } @@ -1343,49 +1350,88 @@ impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { } } +// A custom iterator used by Predicate::walk_tys. +enum WalkTysIter<'tcx, I, J, K> + where I: Iterator>, + J: Iterator>, + K: Iterator> +{ + None, + One(Ty<'tcx>), + Two(Ty<'tcx>, Ty<'tcx>), + Types(I), + InputTypes(J), + ProjectionTypes(K) +} + +impl<'tcx, I, J, K> Iterator for WalkTysIter<'tcx, I, J, K> + where I: Iterator>, + J: Iterator>, + K: Iterator> +{ + type Item = Ty<'tcx>; + + fn next(&mut self) -> Option> { + match *self { + WalkTysIter::None => None, + WalkTysIter::One(item) => { + *self = WalkTysIter::None; + Some(item) + }, + WalkTysIter::Two(item1, item2) => { + *self = WalkTysIter::One(item2); + Some(item1) + }, + WalkTysIter::Types(ref mut iter) => { + iter.next() + }, + WalkTysIter::InputTypes(ref mut iter) => { + iter.next() + }, + WalkTysIter::ProjectionTypes(ref mut iter) => { + iter.next() + } + } + } +} + impl<'tcx> Predicate<'tcx> { /// Iterates over the types in this predicate. Note that in all /// cases this is skipping over a binder, so late-bound regions /// with depth 0 are bound by the predicate. - pub fn walk_tys(&self) -> IntoIter> { - let vec: Vec<_> = match *self { + pub fn walk_tys(&'a self) -> impl Iterator> + 'a { + match *self { ty::Predicate::Trait(ref data) => { - data.skip_binder().input_types().collect() + WalkTysIter::InputTypes(data.skip_binder().input_types()) } ty::Predicate::Subtype(binder) => { let SubtypePredicate { a, b, a_is_expected: _ } = binder.skip_binder(); - vec![a, b] + WalkTysIter::Two(a, b) } ty::Predicate::TypeOutlives(binder) => { - vec![binder.skip_binder().0] + WalkTysIter::One(binder.skip_binder().0) } ty::Predicate::RegionOutlives(..) => { - vec![] + WalkTysIter::None } ty::Predicate::Projection(ref data) => { let inner = data.skip_binder(); - inner.projection_ty.substs.types().chain(Some(inner.ty)).collect() + WalkTysIter::ProjectionTypes( + inner.projection_ty.substs.types().chain(Some(inner.ty))) } ty::Predicate::WellFormed(data) => { - vec![data] + WalkTysIter::One(data) } ty::Predicate::ObjectSafe(_trait_def_id) => { - vec![] + WalkTysIter::None } ty::Predicate::ClosureKind(_closure_def_id, closure_substs, _kind) => { - closure_substs.substs.types().collect() + WalkTysIter::Types(closure_substs.substs.types()) } ty::Predicate::ConstEvaluatable(_, substs) => { - substs.types().collect() + WalkTysIter::Types(substs.types()) } - }; - - // FIXME: The only reason to collect into a vector here is that I was - // too lazy to make the full (somewhat complicated) iterator - // type that would be needed here. But I wanted this fn to - // return an iterator conceptually, rather than a `Vec`, so as - // to be closer to `Ty::walk`. - vec.into_iter() + } } pub fn to_opt_poly_trait_ref(&self) -> Option> { @@ -1544,12 +1590,27 @@ impl UniverseIndex { /// universe are just two regions with an unknown relationship to one /// another. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, PartialOrd, Ord)] -pub struct Placeholder { +pub struct Placeholder { pub universe: UniverseIndex, - pub name: BoundRegion, + pub name: T, +} + +impl<'a, 'gcx, T> HashStable> for Placeholder + where T: HashStable> +{ + fn hash_stable( + &self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher + ) { + self.universe.hash_stable(hcx, hasher); + self.name.hash_stable(hcx, hasher); + } } -impl_stable_hash_for!(struct Placeholder { universe, name }); +pub type PlaceholderRegion = Placeholder; + +pub type PlaceholderType = Placeholder; /// When type checking, we use the `ParamEnv` to track /// details about the set of where-clauses that are in scope at this @@ -1631,7 +1692,7 @@ impl<'tcx> ParamEnv<'tcx> { } Reveal::All => { - if value.has_skol() + if value.has_placeholders() || value.needs_infer() || value.has_param_types() || value.has_self_ty() @@ -1998,6 +2059,12 @@ impl ReprOptions { pub fn inhibit_struct_field_reordering_opt(&self) -> bool { !(self.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty() || (self.pack == 1) } + + /// Returns true if this `#[repr()]` should inhibit union abi optimisations + pub fn inhibit_union_abi_opt(&self) -> bool { + self.c() + } + } impl<'a, 'gcx, 'tcx> AdtDef { @@ -2381,6 +2448,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } + Placeholder(..) | Bound(..) | Infer(..) => { bug!("unexpected type `{:?}` in sized_constraint_for_ty", diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index 7fac88a3d78f1..0e3fc62e4ca9a 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -155,6 +155,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::FnDef(..) | // OutlivesFunction (*) ty::FnPtr(_) | // OutlivesFunction (*) ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*) + ty::Placeholder(..) | ty::Bound(..) | ty::Error => { // (*) Bare functions and traits are both binders. In the diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs index 54550b8a2055f..7d3ae64f4fcd6 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -281,7 +281,7 @@ impl<'sess> OnDiskCache<'sess> { // otherwise, abort break; } - interpret_alloc_index.reserve(new_n); + interpret_alloc_index.reserve(new_n - n); for idx in n..new_n { let id = encoder.interpret_allocs_inverse[idx]; let pos = encoder.position() as u32; diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index e92f92dce63d0..d6aeb288b5cdc 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -746,6 +746,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::Infer(_) | ty::Param(..) | ty::Bound(..) | + ty::Placeholder(..) | ty::Never | ty::Foreign(..) => return self }; @@ -792,6 +793,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::Error | ty::Infer(_) | ty::Bound(..) | + ty::Placeholder(..) | ty::Param(..) | ty::Never | ty::Foreign(..) => false, diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index bd3a34cae90f4..3056abba95626 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -201,7 +201,10 @@ pub enum TyKind<'tcx> { Param(ParamTy), /// Bound type variable, used only when preparing a trait query. - Bound(BoundTy), + Bound(ty::DebruijnIndex, BoundTy), + + /// A placeholder type - universally quantified higher-ranked type. + Placeholder(ty::PlaceholderType), /// A type variable used during type checking. Infer(InferTy), @@ -1165,7 +1168,7 @@ pub enum RegionKind { /// A placeholder region - basically the higher-ranked version of ReFree. /// Should not exist after typeck. - RePlaceholder(ty::Placeholder), + RePlaceholder(ty::PlaceholderRegion), /// Empty lifetime is for data that is never accessed. /// Bottom in the region lattice. We treat ReEmpty somewhat @@ -1242,7 +1245,6 @@ newtype_index! { #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct BoundTy { - pub index: DebruijnIndex, pub var: BoundVar, pub kind: BoundTyKind, } @@ -1253,13 +1255,12 @@ pub enum BoundTyKind { Param(InternedString), } -impl_stable_hash_for!(struct BoundTy { index, var, kind }); +impl_stable_hash_for!(struct BoundTy { var, kind }); impl_stable_hash_for!(enum self::BoundTyKind { Anon, Param(a) }); -impl BoundTy { - pub fn new(index: DebruijnIndex, var: BoundVar) -> Self { +impl From for BoundTy { + fn from(var: BoundVar) -> Self { BoundTy { - index, var, kind: BoundTyKind::Anon, } @@ -1462,7 +1463,7 @@ impl RegionKind { } ty::RePlaceholder(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; - flags = flags | TypeFlags::HAS_RE_SKOL; + flags = flags | TypeFlags::HAS_RE_PLACEHOLDER; } ty::ReLateBound(..) => { flags = flags | TypeFlags::HAS_RE_LATE_BOUND; @@ -1890,6 +1891,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { Foreign(..) | Param(_) | Bound(..) | + Placeholder(..) | Infer(_) | Error => {} } @@ -1953,7 +1955,8 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { ty::Infer(ty::TyVar(_)) => false, - ty::Bound(_) | + ty::Bound(..) | + ty::Placeholder(..) | 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 b7f1731ba44e5..3425203989891 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -190,11 +190,12 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { Substs::for_item(tcx, def_id, |param, _| { match param.kind { ty::GenericParamDefKind::Type { .. } => { - tcx.mk_ty(ty::Bound(ty::BoundTy { - index: ty::INNERMOST, - var: ty::BoundVar::from(param.index), - kind: ty::BoundTyKind::Param(param.name), - })).into() + tcx.mk_ty( + ty::Bound(ty::INNERMOST, ty::BoundTy { + var: ty::BoundVar::from(param.index), + kind: ty::BoundTyKind::Param(param.name), + }) + ).into() } ty::GenericParamDefKind::Lifetime => { @@ -584,18 +585,18 @@ impl CanonicalUserSubsts<'tcx> { self.value.substs.iter().zip(BoundVar::new(0)..).all(|(kind, cvar)| { match kind.unpack() { UnpackedKind::Type(ty) => match ty.sty { - ty::Bound(b) => { + ty::Bound(debruijn, b) => { // We only allow a `ty::INNERMOST` index in substitutions. - assert_eq!(b.index, ty::INNERMOST); + assert_eq!(debruijn, ty::INNERMOST); cvar == b.var } _ => false, }, UnpackedKind::Lifetime(r) => match r { - ty::ReLateBound(index, br) => { + ty::ReLateBound(debruijn, br) => { // We only allow a `ty::INNERMOST` index in substitutions. - assert_eq!(*index, ty::INNERMOST); + assert_eq!(*debruijn, ty::INNERMOST); cvar == br.assert_bound_var() } _ => false, diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 3d0c54d6b0a5b..f0885f960516d 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -952,7 +952,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::Bound(..) | - ty::Opaque(..) | ty::Infer(_) | ty::Error => true, + ty::Placeholder(..) | 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 284c595ee2d96..82b95b9df6031 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::Bound(..) | ty::Foreign(..) => { + ty::Placeholder(..) | 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 1336eac63f880..6ae0793d92471 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -259,6 +259,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { ty::Never | ty::Param(_) | ty::Bound(..) | + ty::Placeholder(..) | ty::Foreign(..) => { // WfScalar, WfParameter, etc } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index e44c0c05bb1a6..eea3b54919d52 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -18,7 +18,7 @@ use ty::{Bool, Char, Adt}; use ty::{Error, Str, Array, Slice, Float, FnDef, FnPtr}; 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::{Placeholder, UnnormalizedProjection, Dynamic, Int, Uint, Infer}; use ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind}; use util::nodemap::FxHashSet; @@ -678,8 +678,8 @@ impl<'tcx> fmt::Debug for ty::ClosureUpvar<'tcx> { impl fmt::Debug for ty::UpvarId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "UpvarId({:?};`{}`;{:?})", - self.var_id, - ty::tls::with(|tcx| tcx.hir.name(tcx.hir.hir_to_node_id(self.var_id))), + self.var_path.hir_id, + ty::tls::with(|tcx| tcx.hir.name(tcx.hir.hir_to_node_id(self.var_path.hir_id))), self.closure_expr_id) } } @@ -792,7 +792,7 @@ define_print! { } ty::ReLateBound(_, br) | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | - ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { + ty::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => { write!(f, "{}", br) } ty::ReScope(scope) if cx.identify_regions => { @@ -1110,13 +1110,13 @@ 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) => { + Bound(debruijn, bound_ty) => { match bound_ty.kind { ty::BoundTyKind::Anon => { - if bound_ty.index == ty::INNERMOST { + if debruijn == ty::INNERMOST { write!(f, "^{}", bound_ty.var.index()) } else { - write!(f, "^{}_{}", bound_ty.index.index(), bound_ty.var.index()) + write!(f, "^{}_{}", debruijn.index(), bound_ty.var.index()) } } @@ -1144,6 +1144,9 @@ define_print! { data.print(f, cx)?; write!(f, ")") } + Placeholder(placeholder) => { + write!(f, "Placeholder({:?})", placeholder) + } Opaque(def_id, substs) => { if cx.is_verbose { return write!(f, "Opaque({:?}, {:?})", def_id, substs); diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 78a31ed668fca..21fb0cdf90ad1 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -453,8 +453,8 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { } None } - LpUpvar(ty::UpvarId{ var_id, closure_expr_id: _ }) => { - self.bccx.used_mut_nodes.borrow_mut().insert(var_id); + LpUpvar(ty::UpvarId{ var_path: ty::UpvarPath { hir_id }, closure_expr_id: _ }) => { + self.bccx.used_mut_nodes.borrow_mut().insert(hir_id); None } LpExtend(ref base, mc::McInherited, LpDeref(pointer_kind)) | diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index e1a4473539c8c..cfd530b7e3d09 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -97,7 +97,7 @@ fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, errors: &[MoveErr } } if let NoteClosureEnv(upvar_id) = error.move_from.note { - let var_node_id = bccx.tcx.hir.hir_to_node_id(upvar_id.var_id); + let var_node_id = bccx.tcx.hir.hir_to_node_id(upvar_id.var_path.hir_id); err.span_label(bccx.tcx.hir.span(var_node_id), "captured outer variable"); } diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index d52d78181b77a..d189460d08848 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -846,7 +846,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { MutabilityViolation => { let mut db = self.cannot_assign(error_span, &descr, Origin::Ast); if let mc::NoteClosureEnv(upvar_id) = err.cmt.note { - let node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_id); + let node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_path.hir_id); let sp = self.tcx.hir.span(node_id); let fn_closure_msg = "`Fn` closures cannot capture their enclosing \ environment for modifications"; @@ -1415,7 +1415,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { loan_path: &LoanPath<'tcx>, out: &mut String) { match loan_path.kind { - LpUpvar(ty::UpvarId { var_id: id, closure_expr_id: _ }) => { + LpUpvar(ty::UpvarId { var_path: ty::UpvarPath { hir_id: id}, closure_expr_id: _ }) => { out.push_str(&self.tcx.hir.name(self.tcx.hir.hir_to_node_id(id)).as_str()); } LpVar(id) => { @@ -1533,7 +1533,7 @@ impl<'tcx> fmt::Debug for LoanPath<'tcx> { write!(f, "$({})", ty::tls::with(|tcx| tcx.hir.node_to_string(id))) } - LpUpvar(ty::UpvarId{ var_id, closure_expr_id }) => { + LpUpvar(ty::UpvarId{ var_path: ty::UpvarPath {hir_id: var_id}, closure_expr_id }) => { let s = ty::tls::with(|tcx| { let var_node_id = tcx.hir.hir_to_node_id(var_id); tcx.hir.node_to_string(var_node_id) @@ -1568,9 +1568,9 @@ impl<'tcx> fmt::Display for LoanPath<'tcx> { write!(f, "$({})", ty::tls::with(|tcx| tcx.hir.node_to_user_string(id))) } - LpUpvar(ty::UpvarId{ var_id, closure_expr_id: _ }) => { + LpUpvar(ty::UpvarId{ var_path: ty::UpvarPath { hir_id }, closure_expr_id: _ }) => { let s = ty::tls::with(|tcx| { - let var_node_id = tcx.hir.hir_to_node_id(var_id); + let var_node_id = tcx.hir.hir_to_node_id(hir_id); tcx.hir.node_to_string(var_node_id) }); write!(f, "$({} captured by closure)", s) diff --git a/src/librustc_codegen_llvm/debuginfo/type_names.rs b/src/librustc_codegen_llvm/debuginfo/type_names.rs index eb5ae81b21840..ceefed7392778 100644 --- a/src/librustc_codegen_llvm/debuginfo/type_names.rs +++ b/src/librustc_codegen_llvm/debuginfo/type_names.rs @@ -171,6 +171,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, } ty::Error | ty::Infer(_) | + ty::Placeholder(..) | ty::UnnormalizedProjection(..) | ty::Projection(..) | ty::Bound(..) | diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 0e2d041b1ffdb..82ace620c8ab2 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -727,6 +727,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) | + ty::Placeholder(..) | ty::UnnormalizedProjection(..) | ty::Projection(..) | ty::Opaque(..) | diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 3c4d8e09fc166..4ccd26bee8b88 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -2193,7 +2193,7 @@ impl<'tcx> AnnotatedBorrowFnSignature<'tcx> { match ty.sty { ty::TyKind::Ref(ty::RegionKind::ReLateBound(_, br), _, _) | ty::TyKind::Ref( - ty::RegionKind::RePlaceholder(ty::Placeholder { name: br, .. }), + ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }), _, _, ) => with_highlight_region_for_bound_region(*br, counter, || ty.to_string()), @@ -2207,7 +2207,7 @@ impl<'tcx> AnnotatedBorrowFnSignature<'tcx> { match ty.sty { ty::TyKind::Ref(region, _, _) => match region { ty::RegionKind::ReLateBound(_, br) - | ty::RegionKind::RePlaceholder(ty::Placeholder { name: br, .. }) => { + | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => { with_highlight_region_for_bound_region(*br, counter, || region.to_string()) } _ => region.to_string(), diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 376f445924270..6a1dc50c67a09 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -1230,7 +1230,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { mir: &Mir<'tcx>, _mir_def_id: DefId, longer_fr: RegionVid, - placeholder: ty::Placeholder, + placeholder: ty::PlaceholderRegion, ) { debug!( "check_bound_universal_region(fr={:?}, placeholder={:?})", diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index 2b7ef38d3edf9..69e2c896d33e5 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -150,7 +150,7 @@ crate enum RegionElement { /// A placeholder (e.g., instantiated from a `for<'a> fn(&'a u32)` /// type). - PlaceholderRegion(ty::Placeholder), + PlaceholderRegion(ty::PlaceholderRegion), } /// When we initially compute liveness, we use a bit matrix storing @@ -219,17 +219,17 @@ impl LivenessValues { } } -/// Maps from `ty::Placeholder` values that are used in the rest of +/// Maps from `ty::PlaceholderRegion` values that are used in the rest of /// rustc to the internal `PlaceholderIndex` values that are used in /// NLL. #[derive(Default)] crate struct PlaceholderIndices { - to_index: FxHashMap, - from_index: IndexVec, + to_index: FxHashMap, + from_index: IndexVec, } impl PlaceholderIndices { - crate fn insert(&mut self, placeholder: ty::Placeholder) -> PlaceholderIndex { + crate fn insert(&mut self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex { let PlaceholderIndices { to_index, from_index, @@ -239,11 +239,11 @@ impl PlaceholderIndices { .or_insert_with(|| from_index.push(placeholder)) } - crate fn lookup_index(&self, placeholder: ty::Placeholder) -> PlaceholderIndex { + crate fn lookup_index(&self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex { self.to_index[&placeholder] } - crate fn lookup_placeholder(&self, placeholder: PlaceholderIndex) -> ty::Placeholder { + crate fn lookup_placeholder(&self, placeholder: PlaceholderIndex) -> ty::PlaceholderRegion { self.from_index[placeholder] } @@ -375,7 +375,7 @@ impl RegionValues { crate fn placeholders_contained_in<'a>( &'a self, r: N, - ) -> impl Iterator + 'a { + ) -> impl Iterator + 'a { self.placeholders .row(r) .into_iter() @@ -432,7 +432,7 @@ impl ToElementIndex for RegionVid { } } -impl ToElementIndex for ty::Placeholder { +impl ToElementIndex for ty::PlaceholderRegion { fn add_to_row(self, values: &mut RegionValues, row: N) -> bool { let index = values.placeholder_indices.lookup_index(self); values.placeholders.insert(row, index) 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 06dfd4bc2cc1f..6f4d8c2bef934 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -777,7 +777,7 @@ impl MirTypeckRegionConstraints<'tcx> { fn placeholder_region( &mut self, infcx: &InferCtxt<'_, '_, 'tcx>, - placeholder: ty::Placeholder, + placeholder: ty::PlaceholderRegion, ) -> ty::Region<'tcx> { let placeholder_index = self.placeholder_indices.insert(placeholder); match self.placeholder_index_to_region.get(placeholder_index) { diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs index b82efb29f6e56..cf4f913080783 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs @@ -84,7 +84,10 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, '_, 'tcx> { } } - fn next_placeholder_region(&mut self, placeholder: ty::Placeholder) -> ty::Region<'tcx> { + fn next_placeholder_region( + &mut self, + placeholder: ty::PlaceholderRegion + ) -> ty::Region<'tcx> { if let Some(borrowck_context) = &mut self.borrowck_context { borrowck_context.constraints.placeholder_region(self.infcx, placeholder) } else { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index a01f8940a948a..0aa1924c0e59c 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -664,7 +664,7 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let var_hir_id = tcx.hir.node_to_hir_id(var_id); let closure_expr_id = tcx.hir.local_def_id(fn_id); let capture = hir.tables().upvar_capture(ty::UpvarId { - var_id: var_hir_id, + var_path: ty::UpvarPath {hir_id: var_hir_id}, closure_expr_id: LocalDefId::from_def_id(closure_expr_id), }); let by_ref = match capture { diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 656a467fb4912..2e9edf20c5708 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -1061,7 +1061,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // ...but the upvar might be an `&T` or `&mut T` capture, at which // point we need an implicit deref let upvar_id = ty::UpvarId { - var_id: var_hir_id, + var_path: ty::UpvarPath {hir_id: var_hir_id}, closure_expr_id: LocalDefId::from_def_id(closure_def_id), }; match cx.tables().upvar_capture(upvar_id) { @@ -1178,7 +1178,7 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, -> ExprRef<'tcx> { let var_hir_id = cx.tcx.hir.node_to_hir_id(freevar.var_id()); let upvar_id = ty::UpvarId { - var_id: var_hir_id, + var_path: ty::UpvarPath { hir_id: var_hir_id }, closure_expr_id: cx.tcx.hir.local_def_id(closure_expr.id).to_local(), }; let upvar_capture = cx.tables().upvar_capture(upvar_id); diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index e6267012dc275..ca09857bbd5ff 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -341,8 +341,21 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc // the last field). Can't have foreign types here, how would we // adjust alignment and size for them? let field = layout.field(self, layout.fields.count() - 1)?; - let (unsized_size, unsized_align) = self.size_and_align_of(metadata, field)? - .expect("Fields cannot be extern types"); + let (unsized_size, unsized_align) = match self.size_and_align_of(metadata, field)? { + Some(size_and_align) => size_and_align, + None => { + // A field with extern type. If this field is at offset 0, we behave + // like the underlying extern type. + // FIXME: Once we have made decisions for how to handle size and alignment + // of `extern type`, this should be adapted. It is just a temporary hack + // to get some code to work that probably ought to work. + if sized_size == Size::ZERO { + return Ok(None) + } else { + bug!("Fields cannot be extern types, unless they are at offset 0") + } + } + }; // FIXME (#26403, #27023): We should be adding padding // to `sized_size` (to accommodate the `unsized_align` diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index e125927e7d273..c5a242f334c90 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -28,7 +28,7 @@ use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use syntax::ast::Mutability; use super::{ - Pointer, AllocId, Allocation, ConstValue, GlobalId, AllocationExtra, + Pointer, AllocId, Allocation, ConstValue, GlobalId, AllocationExtra, InboundsCheck, EvalResult, Scalar, EvalErrorKind, AllocType, PointerArithmetic, Machine, AllocMap, MayLeak, ScalarMaybeUndef, ErrorHandled, }; @@ -249,17 +249,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { // Check non-NULL/Undef, extract offset let (offset, alloc_align) = match ptr { Scalar::Ptr(ptr) => { - let (size, align) = self.get_size_and_align(ptr.alloc_id); // check this is not NULL -- which we can ensure only if this is in-bounds // of some (potentially dead) allocation. - if ptr.offset > size { - return err!(PointerOutOfBounds { - ptr: ptr.erase_tag(), - access: true, - allocation_size: size, - }); - }; - // keep data for alignment check + self.check_bounds_ptr(ptr, InboundsCheck::MaybeDead)?; + // data required for alignment check + let (_, align) = self.get_size_and_align(ptr.alloc_id); (ptr.offset.bytes(), align) } Scalar::Bits { bits, size } => { @@ -293,18 +287,28 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { /// Check if the pointer is "in-bounds". Notice that a pointer pointing at the end /// of an allocation (i.e., at the first *inaccessible* location) *is* considered - /// in-bounds! This follows C's/LLVM's rules. The `access` boolean is just used - /// for the error message. - /// If you want to check bounds before doing a memory access, be sure to - /// check the pointer one past the end of your access, then everything will - /// work out exactly. - pub fn check_bounds_ptr(&self, ptr: Pointer, access: bool) -> EvalResult<'tcx> { - let alloc = self.get(ptr.alloc_id)?; - let allocation_size = alloc.bytes.len() as u64; + /// in-bounds! This follows C's/LLVM's rules. `check` indicates whether we + /// additionally require the pointer to be pointing to a *live* (still allocated) + /// allocation. + /// If you want to check bounds before doing a memory access, better use `check_bounds`. + pub fn check_bounds_ptr( + &self, + ptr: Pointer, + check: InboundsCheck, + ) -> EvalResult<'tcx> { + let allocation_size = match check { + InboundsCheck::Live => { + let alloc = self.get(ptr.alloc_id)?; + alloc.bytes.len() as u64 + } + InboundsCheck::MaybeDead => { + self.get_size_and_align(ptr.alloc_id).0.bytes() + } + }; if ptr.offset.bytes() > allocation_size { return err!(PointerOutOfBounds { ptr: ptr.erase_tag(), - access, + check, allocation_size: Size::from_bytes(allocation_size), }); } @@ -317,10 +321,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { &self, ptr: Pointer, size: Size, - access: bool + check: InboundsCheck, ) -> EvalResult<'tcx> { // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) - self.check_bounds_ptr(ptr.offset(size, &*self)?, access) + self.check_bounds_ptr(ptr.offset(size, &*self)?, check) } } @@ -626,7 +630,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { ) -> EvalResult<'tcx, &[u8]> { assert_ne!(size.bytes(), 0, "0-sized accesses should never even get a `Pointer`"); self.check_align(ptr.into(), align)?; - self.check_bounds(ptr, size, true)?; + self.check_bounds(ptr, size, InboundsCheck::Live)?; if check_defined_and_ptr { self.check_defined(ptr, size)?; @@ -677,7 +681,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { ) -> EvalResult<'tcx, &mut [u8]> { assert_ne!(size.bytes(), 0, "0-sized accesses should never even get a `Pointer`"); self.check_align(ptr.into(), align)?; - self.check_bounds(ptr, size, true)?; + self.check_bounds(ptr, size, InboundsCheck::Live)?; self.mark_definedness(ptr, size, true)?; self.clear_relocations(ptr, size)?; diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index 82fe08fa038a4..96ea0d5094966 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -39,6 +39,6 @@ pub use self::machine::{Machine, AllocMap, MayLeak}; pub use self::operand::{ScalarMaybeUndef, Immediate, ImmTy, Operand, OpTy}; -pub use self::visitor::ValueVisitor; +pub use self::visitor::{ValueVisitor, MutValueVisitor}; pub use self::validity::RefTracking; diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 578bcdc09295d..b7910ad3bce9e 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -19,7 +19,7 @@ use rustc::ty::layout::{self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerEx use rustc::mir::interpret::{ GlobalId, AllocId, ConstValue, Pointer, Scalar, - EvalResult, EvalErrorKind + EvalResult, EvalErrorKind, InboundsCheck, }; use super::{EvalContext, Machine, MemPlace, MPlaceTy, MemoryKind}; pub use rustc::mir::interpret::ScalarMaybeUndef; @@ -601,7 +601,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> // read raw discriminant value let discr_op = self.operand_field(rval, 0)?; let discr_val = self.read_immediate(discr_op)?; - let raw_discr = discr_val.to_scalar()?; + let raw_discr = discr_val.to_scalar_or_undef(); trace!("discr value: {:?}", raw_discr); // post-process Ok(match rval.layout.variants { @@ -647,28 +647,33 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> let variants_start = niche_variants.start().as_u32() as u128; let variants_end = niche_variants.end().as_u32() as u128; match raw_discr { - Scalar::Ptr(_) => { - // The niche must be just 0 (which a pointer value never is) - assert!(niche_start == 0); - assert!(variants_start == variants_end); + ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) => { + // The niche must be just 0 (which an inbounds pointer value never is) + let ptr_valid = niche_start == 0 && variants_start == variants_end && + self.memory.check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok(); + if !ptr_valid { + return err!(InvalidDiscriminant(raw_discr.erase_tag())); + } (dataful_variant.as_u32() as u128, dataful_variant) }, - Scalar::Bits { bits: raw_discr, size } => { + ScalarMaybeUndef::Scalar(Scalar::Bits { bits: raw_discr, size }) => { assert_eq!(size as u64, discr_val.layout.size.bytes()); - let discr = raw_discr.wrapping_sub(niche_start) + let adjusted_discr = raw_discr.wrapping_sub(niche_start) .wrapping_add(variants_start); - if variants_start <= discr && discr <= variants_end { - let index = discr as usize; - assert_eq!(index as u128, discr); + if variants_start <= adjusted_discr && adjusted_discr <= variants_end { + let index = adjusted_discr as usize; + assert_eq!(index as u128, adjusted_discr); assert!(index < rval.layout.ty .ty_adt_def() .expect("tagged layout for non adt") .variants.len()); - (discr, VariantIdx::from_usize(index)) + (adjusted_discr, VariantIdx::from_usize(index)) } else { (dataful_variant.as_u32() as u128, dataful_variant) } }, + ScalarMaybeUndef::Undef => + return err!(InvalidDiscriminant(ScalarMaybeUndef::Undef)), } } }) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 201d320dcd858..fa76eeb2fedd5 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -351,8 +351,17 @@ where // Offset may need adjustment for unsized fields let (meta, offset) = if field_layout.is_unsized() { // re-use parent metadata to determine dynamic field layout - let (_, align) = self.size_and_align_of(base.meta, field_layout)? - .expect("Fields cannot be extern types"); + let align = match self.size_and_align_of(base.meta, field_layout)? { + Some((_, align)) => align, + None if offset == Size::ZERO => + // An extern type at offset 0, we fall back to its static alignment. + // FIXME: Once we have made decisions for how to handle size and alignment + // of `extern type`, this should be adapted. It is just a temporary hack + // to get some code to work that probably ought to work. + field_layout.align, + None => + bug!("Cannot compute offset for extern type field at non-0 offset"), + }; (base.meta, offset.abi_align(align)) } else { // base.meta could be present; we might be accessing a sized field of an unsized diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 988ff7e75163d..ad7ffd291bed1 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -17,11 +17,11 @@ use rustc::ty::layout::{self, Size, Align, TyLayout, LayoutOf, VariantIdx}; use rustc::ty; use rustc_data_structures::fx::FxHashSet; use rustc::mir::interpret::{ - Scalar, AllocType, EvalResult, EvalErrorKind, + Scalar, AllocType, EvalResult, EvalErrorKind, InboundsCheck, }; use super::{ - OpTy, MPlaceTy, ImmTy, Machine, EvalContext, ValueVisitor + OpTy, MPlaceTy, Machine, EvalContext, ValueVisitor }; macro_rules! validation_failure { @@ -274,15 +274,16 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> ), EvalErrorKind::ReadPointerAsBytes => validation_failure!( - "a pointer", self.path, "plain bytes" + "a pointer", self.path, "plain (non-pointer) bytes" ), _ => Err(err), } } } - fn visit_primitive(&mut self, value: ImmTy<'tcx, M::PointerTag>) -> EvalResult<'tcx> + fn visit_primitive(&mut self, value: OpTy<'tcx, M::PointerTag>) -> EvalResult<'tcx> { + let value = self.ecx.read_immediate(value)?; // Go over all the primitive types let ty = value.layout.ty; match ty.sty { @@ -304,7 +305,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> if self.const_mode { // Integers/floats in CTFE: Must be scalar bits, pointers are dangerous try_validation!(value.to_bits(size), - value, self.path, "initialized plain bits"); + value, self.path, "initialized plain (non-pointer) bytes"); } else { // At run-time, for now, we accept *anything* for these types, including // undef. We should fix that, but let's start low. @@ -394,7 +395,8 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> } // Maintain the invariant that the place we are checking is // already verified to be in-bounds. - try_validation!(self.ecx.memory.check_bounds(ptr, size, false), + try_validation!( + self.ecx.memory.check_bounds(ptr, size, InboundsCheck::Live), "dangling (not entirely in bounds) reference", self.path); } // Check if we have encountered this pointer+layout combination diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs index 4a47045643253..f0a71242599bf 100644 --- a/src/librustc_mir/interpret/visitor.rs +++ b/src/librustc_mir/interpret/visitor.rs @@ -8,7 +8,7 @@ use rustc::mir::interpret::{ }; use super::{ - Machine, EvalContext, MPlaceTy, OpTy, ImmTy, + Machine, EvalContext, MPlaceTy, OpTy, }; // A thing that we can project into, and that has a layout. @@ -201,9 +201,11 @@ macro_rules! make_value_visitor { { Ok(()) } /// Called whenever we reach a value of primitive type. There can be no recursion - /// below such a value. This is the leave function. + /// below such a value. This is the leaf function. + /// We do *not* provide an `ImmTy` here because some implementations might want + /// to write to the place this primitive lives in. #[inline(always)] - fn visit_primitive(&mut self, _val: ImmTy<'tcx, M::PointerTag>) -> EvalResult<'tcx> + fn visit_primitive(&mut self, _v: Self::V) -> EvalResult<'tcx> { Ok(()) } // Default recursors. Not meant to be overloaded. @@ -279,9 +281,7 @@ macro_rules! make_value_visitor { _ => v.layout().ty.builtin_deref(true).is_some(), }; if primitive { - let op = v.to_op(self.ecx())?; - let val = self.ecx().read_immediate(op)?; - return self.visit_primitive(val); + return self.visit_primitive(v); } // Proceed into the fields. diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 9d69a5669b1c0..cf754df750195 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -384,6 +384,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { ty::Error | ty::Bound(..) | ty::Infer(_) | + ty::Placeholder(..) | ty::UnnormalizedProjection(..) | ty::Projection(..) | ty::Param(_) | diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 0c0f50c1fd709..15c8861eb3f1f 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -658,11 +658,13 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { impl_items: &'l [ast::ImplItem], ) { if let Some(impl_data) = self.save_ctxt.get_item_data(item) { - if let super::Data::RelationData(rel, imp) = impl_data { - self.dumper.dump_relation(rel); - self.dumper.dump_impl(imp); - } else { - span_bug!(item.span, "unexpected data kind: {:?}", impl_data); + if !self.span.filter_generated(item.span) { + if let super::Data::RelationData(rel, imp) = impl_data { + self.dumper.dump_relation(rel); + self.dumper.dump_impl(imp); + } else { + span_bug!(item.span, "unexpected data kind: {:?}", impl_data); + } } } self.visit_ty(&typ); diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index 902353da13f76..06b4f33b5db3e 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -124,14 +124,10 @@ impl<'a> SpanUtils<'a> { /// Used to filter out spans of minimal value, /// such as references to macro internal variables. pub fn filter_generated(&self, span: Span) -> bool { - if span.is_dummy() { + if generated_code(span) { return true; } - if !generated_code(span) { - return false; - } - //If the span comes from a fake source_file, filter it. !self.sess .source_map() diff --git a/src/librustc_traits/chalk_context/mod.rs b/src/librustc_traits/chalk_context/mod.rs index 0fd9f607a5462..25a6af284b572 100644 --- a/src/librustc_traits/chalk_context/mod.rs +++ b/src/librustc_traits/chalk_context/mod.rs @@ -11,7 +11,7 @@ mod program_clauses; use chalk_engine::fallible::Fallible as ChalkEngineFallible; -use chalk_engine::{context, hh::HhGoal, DelayedLiteral, ExClause}; +use chalk_engine::{context, hh::HhGoal, DelayedLiteral, Literal, ExClause}; use rustc::infer::canonical::{ Canonical, CanonicalVarValues, OriginalQueryValues, QueryRegionConstraint, QueryResponse, }; @@ -28,7 +28,7 @@ use rustc::traits::{ InEnvironment, }; use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use rustc::ty::subst::Kind; +use rustc::ty::subst::{Kind, UnpackedKind}; use rustc::ty::{self, TyCtxt}; use std::fmt::{self, Debug}; @@ -44,7 +44,7 @@ crate struct ChalkArenas<'gcx> { #[derive(Copy, Clone)] crate struct ChalkContext<'cx, 'gcx: 'cx> { _arenas: ChalkArenas<'gcx>, - _tcx: TyCtxt<'cx, 'gcx, 'gcx>, + tcx: TyCtxt<'cx, 'gcx, 'gcx>, } #[derive(Copy, Clone)] @@ -68,7 +68,7 @@ BraceStructTypeFoldableImpl! { } impl context::Context for ChalkArenas<'tcx> { - type CanonicalExClause = Canonical<'tcx, ExClause>; + type CanonicalExClause = Canonical<'tcx, ChalkExClause<'tcx>>; type CanonicalGoalInEnvironment = Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>; @@ -147,19 +147,29 @@ impl context::ContextOps> for ChalkContext<'cx, 'gcx> { /// - the environment and goal found by substitution `S` into `arg` fn instantiate_ucanonical_goal( &self, - _arg: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>, - _op: impl context::WithInstantiatedUCanonicalGoal, Output = R>, + arg: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>, + op: impl context::WithInstantiatedUCanonicalGoal, Output = R>, ) -> R { - unimplemented!() + self.tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, arg, |ref infcx, arg, subst| { + let chalk_infcx = &mut ChalkInferenceContext { + infcx, + }; + op.with(chalk_infcx, subst, arg.environment, arg.goal) + }) } fn instantiate_ex_clause( &self, _num_universes: usize, - _canonical_ex_clause: &Canonical<'gcx, ChalkExClause<'gcx>>, - _op: impl context::WithInstantiatedExClause, Output = R>, + arg: &Canonical<'gcx, ChalkExClause<'gcx>>, + op: impl context::WithInstantiatedExClause, Output = R>, ) -> R { - unimplemented!() + self.tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &arg.upcast(), |ref infcx, arg, _| { + let chalk_infcx = &mut ChalkInferenceContext { + infcx, + }; + op.with(chalk_infcx,arg) + }) } /// True if this solution has no region constraints. @@ -186,14 +196,33 @@ impl context::ContextOps> for ChalkContext<'cx, 'gcx> { } fn is_trivial_substitution( - _u_canon: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>, - _canonical_subst: &Canonical<'gcx, ConstrainedSubst<'gcx>>, + u_canon: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>, + canonical_subst: &Canonical<'tcx, ConstrainedSubst<'tcx>>, ) -> bool { - unimplemented!() - } - - fn num_universes(_: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>) -> usize { - 0 // FIXME + let subst = &canonical_subst.value.subst; + assert_eq!(u_canon.variables.len(), subst.var_values.len()); + subst.var_values + .iter_enumerated() + .all(|(cvar, kind)| match kind.unpack() { + UnpackedKind::Lifetime(r) => match r { + &ty::ReLateBound(debruijn, br) => { + debug_assert_eq!(debruijn, ty::INNERMOST); + cvar == br.assert_bound_var() + } + _ => false, + }, + UnpackedKind::Type(ty) => match ty.sty { + ty::Bound(debruijn, bound_ty) => { + debug_assert_eq!(debruijn, ty::INNERMOST); + cvar == bound_ty.var + } + _ => false, + }, + }) + } + + fn num_universes(canon: &Canonical<'gcx, InEnvironment<'gcx, Goal<'gcx>>>) -> usize { + canon.max_universe.index() + 1 } /// Convert a goal G *from* the canonical universes *into* our @@ -214,39 +243,6 @@ impl context::ContextOps> for ChalkContext<'cx, 'gcx> { } } -//impl context::UCanonicalGoalInEnvironment> -// for Canonical<'gcx, ty::ParamEnvAnd<'gcx, Goal<'gcx>>> -//{ -// fn canonical(&self) -> &Canonical<'gcx, ty::ParamEnvAnd<'gcx, Goal<'gcx>>> { -// self -// } -// -// fn is_trivial_substitution( -// &self, -// canonical_subst: &Canonical<'tcx, ConstrainedSubst<'tcx>>, -// ) -> bool { -// let subst = &canonical_subst.value.subst; -// assert_eq!(self.canonical.variables.len(), subst.var_values.len()); -// subst -// .var_values -// .iter_enumerated() -// .all(|(cvar, kind)| match kind.unpack() { -// Kind::Lifetime(r) => match r { -// ty::ReCanonical(cvar1) => cvar == cvar1, -// _ => false, -// }, -// Kind::Type(ty) => match ty.sty { -// ty::Infer(ty::InferTy::CanonicalTy(cvar1)) => cvar == cvar1, -// _ => false, -// }, -// }) -// } -// -// fn num_universes(&self) -> usize { -// 0 // FIXME -// } -//} - impl context::InferenceTable, ChalkArenas<'tcx>> for ChalkInferenceContext<'cx, 'gcx, 'tcx> { @@ -260,7 +256,10 @@ impl context::InferenceTable, ChalkArenas<'tcx>> fn into_hh_goal(&mut self, goal: Goal<'tcx>) -> ChalkHhGoal<'tcx> { match *goal { - GoalKind::Implies(..) => panic!("FIXME rust-lang-nursery/chalk#94"), + GoalKind::Implies(hypotheses, goal) => HhGoal::Implies( + hypotheses.iter().cloned().collect(), + goal + ), GoalKind::And(left, right) => HhGoal::And(left, right), GoalKind::Not(subgoal) => HhGoal::Not(subgoal), GoalKind::DomainGoal(d) => HhGoal::DomainGoal(d), @@ -338,9 +337,9 @@ impl context::UnificationOps, ChalkArenas<'tcx>> fn instantiate_binders_universally( &mut self, - _arg: &ty::Binder>, + arg: &ty::Binder>, ) -> Goal<'tcx> { - panic!("FIXME -- universal instantiation needs sgrif's branch") + self.infcx.replace_bound_vars_with_placeholders(arg).0 } fn instantiate_binders_existentially( @@ -491,3 +490,68 @@ BraceStructLiftImpl! { subst, constraints } } + +trait Upcast<'tcx, 'gcx: 'tcx>: 'gcx { + type Upcasted: 'tcx; + + fn upcast(&self) -> Self::Upcasted; +} + +impl<'tcx, 'gcx: 'tcx> Upcast<'tcx, 'gcx> for DelayedLiteral> { + type Upcasted = DelayedLiteral>; + + fn upcast(&self) -> Self::Upcasted { + match self { + &DelayedLiteral::CannotProve(..) => DelayedLiteral::CannotProve(()), + &DelayedLiteral::Negative(index) => DelayedLiteral::Negative(index), + DelayedLiteral::Positive(index, subst) => DelayedLiteral::Positive( + *index, + subst.clone() + ), + } + } +} + +impl<'tcx, 'gcx: 'tcx> Upcast<'tcx, 'gcx> for Literal> { + type Upcasted = Literal>; + + fn upcast(&self) -> Self::Upcasted { + match self { + &Literal::Negative(goal) => Literal::Negative(goal), + &Literal::Positive(goal) => Literal::Positive(goal), + } + } +} + +impl<'tcx, 'gcx: 'tcx> Upcast<'tcx, 'gcx> for ExClause> { + type Upcasted = ExClause>; + + fn upcast(&self) -> Self::Upcasted { + ExClause { + subst: self.subst.clone(), + delayed_literals: self.delayed_literals + .iter() + .map(|l| l.upcast()) + .collect(), + constraints: self.constraints.clone(), + subgoals: self.subgoals + .iter() + .map(|g| g.upcast()) + .collect(), + } + } +} + +impl<'tcx, 'gcx: 'tcx, T> Upcast<'tcx, 'gcx> for Canonical<'gcx, T> + where T: Upcast<'tcx, 'gcx> +{ + type Upcasted = Canonical<'tcx, T::Upcasted>; + + fn upcast(&self) -> Self::Upcasted { + Canonical { + max_universe: self.max_universe, + value: self.value.upcast(), + variables: self.variables, + } + } +} diff --git a/src/librustc_traits/chalk_context/program_clauses.rs b/src/librustc_traits/chalk_context/program_clauses.rs index 31f97b72e1927..b8670e5e91436 100644 --- a/src/librustc_traits/chalk_context/program_clauses.rs +++ b/src/librustc_traits/chalk_context/program_clauses.rs @@ -59,7 +59,8 @@ fn assemble_clauses_from_assoc_ty_values<'tcx>( fn program_clauses_for_raw_ptr<'tcx>(tcx: ty::TyCtxt<'_, '_, 'tcx>) -> Clauses<'tcx> { let ty = ty::Bound( - ty::BoundTy::new(ty::INNERMOST, ty::BoundVar::from_u32(0)) + ty::INNERMOST, + ty::BoundVar::from_u32(0).into() ); let ty = tcx.mk_ty(ty); @@ -88,9 +89,9 @@ fn program_clauses_for_fn_ptr<'tcx>( ) -> Clauses<'tcx> { let inputs_and_output = tcx.mk_type_list( (0..arity_and_output).into_iter() + .map(|i| ty::BoundVar::from(i)) // DebruijnIndex(1) because we are going to inject these in a `PolyFnSig` - .map(|i| ty::BoundTy::new(ty::DebruijnIndex::from(1usize), ty::BoundVar::from(i))) - .map(|t| tcx.mk_ty(ty::Bound(t))) + .map(|var| tcx.mk_ty(ty::Bound(ty::DebruijnIndex::from(1usize), var.into()))) ); let fn_sig = ty::Binder::bind(ty::FnSig { @@ -115,7 +116,8 @@ fn program_clauses_for_fn_ptr<'tcx>( fn program_clauses_for_slice<'tcx>(tcx: ty::TyCtxt<'_, '_, 'tcx>) -> Clauses<'tcx> { let ty = ty::Bound( - ty::BoundTy::new(ty::INNERMOST, ty::BoundVar::from_u32(0)) + ty::INNERMOST, + ty::BoundVar::from_u32(0).into() ); let ty = tcx.mk_ty(ty); @@ -151,7 +153,8 @@ fn program_clauses_for_array<'tcx>( length: &'tcx ty::Const<'tcx> ) -> Clauses<'tcx> { let ty = ty::Bound( - ty::BoundTy::new(ty::INNERMOST, ty::BoundVar::from_u32(0)) + ty::INNERMOST, + ty::BoundVar::from_u32(0).into() ); let ty = tcx.mk_ty(ty); @@ -188,8 +191,8 @@ fn program_clauses_for_tuple<'tcx>( ) -> Clauses<'tcx> { let type_list = tcx.mk_type_list( (0..arity).into_iter() - .map(|i| ty::BoundTy::new(ty::INNERMOST, ty::BoundVar::from(i))) - .map(|t| tcx.mk_ty(ty::Bound(t))) + .map(|i| ty::BoundVar::from(i)) + .map(|var| tcx.mk_ty(ty::Bound(ty::INNERMOST, var.into()))) ); let tuple_ty = tcx.mk_ty(ty::Tuple(type_list)); @@ -233,7 +236,7 @@ fn program_clauses_for_ref<'tcx>(tcx: ty::TyCtxt<'_, '_, 'tcx>) -> Clauses<'tcx> ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(0)) ); let ty = tcx.mk_ty( - ty::Bound(ty::BoundTy::new(ty::INNERMOST, ty::BoundVar::from_u32(1))) + ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(1).into()) ); let ref_ty = tcx.mk_ref(region, ty::TypeAndMut { @@ -418,6 +421,7 @@ impl ChalkInferenceContext<'cx, 'gcx, 'tcx> { } ty::GeneratorWitness(..) | + ty::Placeholder(..) | ty::UnnormalizedProjection(..) | ty::Infer(..) | ty::Bound(..) | diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs index af64522f18398..9ab86daf65449 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::Bound(..) | ty::Infer(..) | ty::Error => { + ty::Placeholder(..) | 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/lowering/environment.rs b/src/librustc_traits/lowering/environment.rs index 54f0c6e8da78a..519b0ac61058e 100644 --- a/src/librustc_traits/lowering/environment.rs +++ b/src/librustc_traits/lowering/environment.rs @@ -55,7 +55,7 @@ impl ClauseVisitor<'set, 'a, 'tcx> { ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(0)) ); let ty = self.tcx.mk_ty( - ty::Bound(ty::BoundTy::new(ty::INNERMOST, ty::BoundVar::from_u32(1))) + ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(1).into()) ); let ref_ty = self.tcx.mk_ref(region, ty::TypeAndMut { @@ -114,6 +114,7 @@ impl ClauseVisitor<'set, 'a, 'tcx> { ty::Tuple(..) | ty::Never | ty::Infer(..) | + ty::Placeholder(..) | ty::Bound(..) => (), ty::GeneratorWitness(..) | diff --git a/src/librustc_traits/lowering/mod.rs b/src/librustc_traits/lowering/mod.rs index cf1bc04dd4e01..2d8e5b48aac7b 100644 --- a/src/librustc_traits/lowering/mod.rs +++ b/src/librustc_traits/lowering/mod.rs @@ -515,7 +515,8 @@ pub fn program_clauses_for_associated_type_def<'a, 'tcx>( .unwrap_or(0); // Add a new type param after the existing ones (`U` in the comment above). let ty_var = ty::Bound( - ty::BoundTy::new(ty::INNERMOST, ty::BoundVar::from_u32(offset + 1)) + ty::INNERMOST, + ty::BoundVar::from_u32(offset + 1).into() ); // `ProjectionEq(>::AssocType = U)` diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 3f0a353124442..c35aee7883f49 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::Bound(..) | ty::Infer(_) => None, + ty::Placeholder(..) | 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/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 0373bf4e7522d..5b67116cb511e 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1494,7 +1494,7 @@ impl<'tcx> Candidate<'tcx> { // `WhereClausePick`. assert!( !trait_ref.skip_binder().substs.needs_infer() - && !trait_ref.skip_binder().substs.has_skol() + && !trait_ref.skip_binder().substs.has_placeholders() ); WhereClausePick(trait_ref.clone()) diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index df994ad9e55c4..312ce402775d2 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -45,14 +45,14 @@ use super::FnCtxt; use middle::expr_use_visitor as euv; use middle::mem_categorization as mc; use middle::mem_categorization::Categorization; +use rustc::hir; use rustc::hir::def_id::DefId; -use rustc::ty::{self, Ty, TyCtxt, UpvarSubsts}; +use rustc::hir::def_id::LocalDefId; +use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::infer::UpvarRegion; +use rustc::ty::{self, Ty, TyCtxt, UpvarSubsts}; use syntax::ast; use syntax_pos::Span; -use rustc::hir; -use rustc::hir::def_id::LocalDefId; -use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn closure_analyze(&self, body: &'gcx hir::Body) { @@ -121,7 +121,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; - let infer_kind = if let UpvarSubsts::Closure(closure_substs) = substs{ + let infer_kind = if let UpvarSubsts::Closure(closure_substs) = substs { if self.closure_kind(closure_def_id, closure_substs).is_none() { Some(closure_substs) } else { @@ -134,7 +134,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.tcx.with_freevars(closure_node_id, |freevars| { for freevar in freevars { let upvar_id = ty::UpvarId { - var_id: self.tcx.hir.node_to_hir_id(freevar.var_id()), + var_path: ty::UpvarPath { + hir_id : self.tcx.hir.node_to_hir_id(freevar.var_id()), + }, closure_expr_id: LocalDefId::from_def_id(closure_def_id), }; debug!("seed upvar_id {:?}", upvar_id); @@ -213,12 +215,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let final_upvar_tys = self.final_upvar_tys(closure_node_id); debug!( "analyze_closure: id={:?} substs={:?} final_upvar_tys={:?}", - closure_node_id, - substs, - final_upvar_tys + closure_node_id, substs, final_upvar_tys ); - for (upvar_ty, final_upvar_ty) in substs.upvar_tys(closure_def_id, self.tcx) - .zip(final_upvar_tys) + for (upvar_ty, final_upvar_ty) in substs + .upvar_tys(closure_def_id, self.tcx) + .zip(final_upvar_tys) { self.demand_suptype(span, upvar_ty, final_upvar_ty); } @@ -249,16 +250,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let var_hir_id = tcx.hir.node_to_hir_id(var_node_id); let freevar_ty = self.node_ty(var_hir_id); let upvar_id = ty::UpvarId { - var_id: var_hir_id, + var_path: ty::UpvarPath { + hir_id: var_hir_id, + }, closure_expr_id: LocalDefId::from_def_id(closure_def_index), }; let capture = self.tables.borrow().upvar_capture(upvar_id); debug!( "var_id={:?} freevar_ty={:?} capture={:?}", - var_node_id, - freevar_ty, - capture + var_node_id, freevar_ty, capture ); match capture { @@ -271,8 +272,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }, ), } - }) - .collect() + }).collect() }) } } @@ -301,12 +301,14 @@ struct InferBorrowKind<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { } impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { - fn adjust_upvar_borrow_kind_for_consume(&mut self, cmt: &mc::cmt_<'tcx>, - mode: euv::ConsumeMode) { + fn adjust_upvar_borrow_kind_for_consume( + &mut self, + cmt: &mc::cmt_<'tcx>, + mode: euv::ConsumeMode, + ) { debug!( "adjust_upvar_borrow_kind_for_consume(cmt={:?}, mode={:?})", - cmt, - mode + cmt, mode ); // we only care about moves @@ -349,7 +351,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { upvar_id.closure_expr_id, ty::ClosureKind::FnOnce, guarantor.span, - var_name(tcx, upvar_id.var_id), + var_name(tcx, upvar_id.var_path.hir_id), ); self.adjust_upvar_captures @@ -366,7 +368,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { upvar_id.closure_expr_id, ty::ClosureKind::FnOnce, guarantor.span, - var_name(tcx, upvar_id.var_id), + var_name(tcx, upvar_id.var_path.hir_id), ); } mc::NoteIndex | mc::NoteNone => {} @@ -381,9 +383,9 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { debug!("adjust_upvar_borrow_kind_for_mut(cmt={:?})", cmt); match cmt.cat.clone() { - Categorization::Deref(base, mc::Unique) | - Categorization::Interior(base, _) | - Categorization::Downcast(base, _) => { + Categorization::Deref(base, mc::Unique) + | Categorization::Interior(base, _) + | Categorization::Downcast(base, _) => { // Interior or owned data is mutable if base is // mutable, so iterate to the base. self.adjust_upvar_borrow_kind_for_mut(&base); @@ -399,12 +401,12 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { } } - Categorization::Deref(_, mc::UnsafePtr(..)) | - Categorization::StaticItem | - Categorization::ThreadLocal(..) | - Categorization::Rvalue(..) | - Categorization::Local(_) | - Categorization::Upvar(..) => { + Categorization::Deref(_, mc::UnsafePtr(..)) + | Categorization::StaticItem + | Categorization::ThreadLocal(..) + | Categorization::Rvalue(..) + | Categorization::Local(_) + | Categorization::Upvar(..) => { return; } } @@ -414,9 +416,9 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { debug!("adjust_upvar_borrow_kind_for_unique(cmt={:?})", cmt); match cmt.cat.clone() { - Categorization::Deref(base, mc::Unique) | - Categorization::Interior(base, _) | - Categorization::Downcast(base, _) => { + Categorization::Deref(base, mc::Unique) + | Categorization::Interior(base, _) + | Categorization::Downcast(base, _) => { // Interior or owned data is unique if base is // unique. self.adjust_upvar_borrow_kind_for_unique(&base); @@ -430,18 +432,20 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { } } - Categorization::Deref(_, mc::UnsafePtr(..)) | - Categorization::StaticItem | - Categorization::ThreadLocal(..) | - Categorization::Rvalue(..) | - Categorization::Local(_) | - Categorization::Upvar(..) => {} + Categorization::Deref(_, mc::UnsafePtr(..)) + | Categorization::StaticItem + | Categorization::ThreadLocal(..) + | Categorization::Rvalue(..) + | Categorization::Local(_) + | Categorization::Upvar(..) => {} } } - fn try_adjust_upvar_deref(&mut self, cmt: &mc::cmt_<'tcx>, borrow_kind: ty::BorrowKind) - -> bool - { + fn try_adjust_upvar_deref( + &mut self, + cmt: &mc::cmt_<'tcx>, + borrow_kind: ty::BorrowKind, + ) -> bool { assert!(match borrow_kind { ty::MutBorrow => true, ty::UniqueImmBorrow => true, @@ -465,7 +469,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { upvar_id.closure_expr_id, ty::ClosureKind::FnMut, cmt.span, - var_name(tcx, upvar_id.var_id), + var_name(tcx, upvar_id.var_path.hir_id), ); true @@ -478,7 +482,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { upvar_id.closure_expr_id, ty::ClosureKind::FnMut, cmt.span, - var_name(tcx, upvar_id.var_id), + var_name(tcx, upvar_id.var_path.hir_id), ); true @@ -493,15 +497,14 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { /// Here the argument `mutbl` is the borrow_kind that is required by /// some particular use. fn adjust_upvar_borrow_kind(&mut self, upvar_id: ty::UpvarId, kind: ty::BorrowKind) { - let upvar_capture = self.adjust_upvar_captures + let upvar_capture = self + .adjust_upvar_captures .get(&upvar_id) .cloned() .unwrap_or_else(|| self.fcx.tables.borrow().upvar_capture(upvar_id)); debug!( "adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})", - upvar_id, - upvar_capture, - kind + upvar_id, upvar_capture, kind ); match upvar_capture { @@ -511,18 +514,18 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { ty::UpvarCapture::ByRef(mut upvar_borrow) => { match (upvar_borrow.kind, kind) { // Take RHS: - (ty::ImmBorrow, ty::UniqueImmBorrow) | - (ty::ImmBorrow, ty::MutBorrow) | - (ty::UniqueImmBorrow, ty::MutBorrow) => { + (ty::ImmBorrow, ty::UniqueImmBorrow) + | (ty::ImmBorrow, ty::MutBorrow) + | (ty::UniqueImmBorrow, ty::MutBorrow) => { upvar_borrow.kind = kind; self.adjust_upvar_captures .insert(upvar_id, ty::UpvarCapture::ByRef(upvar_borrow)); } // Take LHS: - (ty::ImmBorrow, ty::ImmBorrow) | - (ty::UniqueImmBorrow, ty::ImmBorrow) | - (ty::UniqueImmBorrow, ty::UniqueImmBorrow) | - (ty::MutBorrow, _) => {} + (ty::ImmBorrow, ty::ImmBorrow) + | (ty::UniqueImmBorrow, ty::ImmBorrow) + | (ty::UniqueImmBorrow, ty::UniqueImmBorrow) + | (ty::MutBorrow, _) => {} } } } @@ -537,10 +540,7 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { ) { debug!( "adjust_closure_kind(closure_id={:?}, new_kind={:?}, upvar_span={:?}, var_name={})", - closure_id, - new_kind, - upvar_span, - var_name + closure_id, new_kind, upvar_span, var_name ); // Is this the closure whose kind is currently being inferred? @@ -554,22 +554,20 @@ impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { debug!( "adjust_closure_kind: closure_id={:?}, existing_kind={:?}, new_kind={:?}", - closure_id, - existing_kind, - new_kind + closure_id, existing_kind, new_kind ); match (existing_kind, new_kind) { - (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | - (ty::ClosureKind::FnMut, ty::ClosureKind::Fn) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | - (ty::ClosureKind::FnOnce, _) => { + (ty::ClosureKind::Fn, ty::ClosureKind::Fn) + | (ty::ClosureKind::FnMut, ty::ClosureKind::Fn) + | (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) + | (ty::ClosureKind::FnOnce, _) => { // no change needed } - (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) | - (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { + (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) + | (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) + | (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { // new kind is stronger than the old kind self.current_closure_kind = new_kind; self.current_origin = Some((upvar_span, var_name)); @@ -590,12 +588,20 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> { self.adjust_upvar_borrow_kind_for_consume(cmt, mode); } - fn matched_pat(&mut self, _matched_pat: &hir::Pat, _cmt: &mc::cmt_<'tcx>, - _mode: euv::MatchMode) { + fn matched_pat( + &mut self, + _matched_pat: &hir::Pat, + _cmt: &mc::cmt_<'tcx>, + _mode: euv::MatchMode, + ) { } - fn consume_pat(&mut self, _consume_pat: &hir::Pat, cmt: &mc::cmt_<'tcx>, - mode: euv::ConsumeMode) { + fn consume_pat( + &mut self, + _consume_pat: &hir::Pat, + cmt: &mc::cmt_<'tcx>, + mode: euv::ConsumeMode, + ) { debug!("consume_pat(cmt={:?},mode={:?})", cmt, mode); self.adjust_upvar_borrow_kind_for_consume(cmt, mode); } @@ -611,9 +617,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> { ) { debug!( "borrow(borrow_id={}, cmt={:?}, bk={:?})", - borrow_id, - cmt, - bk + borrow_id, cmt, bk ); match bk { diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index d968bf222aa09..382a158bdc802 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -115,7 +115,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { fn write_ty_to_tables(&mut self, hir_id: hir::HirId, ty: Ty<'gcx>) { debug!("write_ty_to_tables({:?}, {:?})", hir_id, ty); - assert!(!ty.needs_infer() && !ty.has_skol()); + assert!(!ty.needs_infer() && !ty.has_placeholders()); self.tables.node_types_mut().insert(hir_id, ty); } @@ -306,7 +306,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue, ty::UpvarCapture::ByRef(ref upvar_borrow) => { let r = upvar_borrow.region; - let r = self.resolve(&r, &upvar_id.var_id); + let r = self.resolve(&r, &upvar_id.var_path.hir_id); ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind: upvar_borrow.kind, region: r, @@ -580,7 +580,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { if let Some(substs) = self.fcx.tables.borrow().node_substs_opt(hir_id) { let substs = self.resolve(&substs, &span); debug!("write_substs_to_tcx({:?}, {:?})", hir_id, substs); - assert!(!substs.needs_infer() && !substs.has_skol()); + assert!(!substs.needs_infer() && !substs.has_placeholders()); self.tables.node_substs_mut().insert(hir_id, substs); } diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 47d34c909961e..ed32e5a8d9b38 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -336,6 +336,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // types, where we use Error as the Self type } + ty::Placeholder(..) | ty::UnnormalizedProjection(..) | ty::GeneratorWitness(..) | ty::Bound(..) | diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0518d73e1e30f..fd8f70b19e7ec 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2744,6 +2744,7 @@ impl<'tcx> Clean for Ty<'tcx> { ty::Closure(..) | ty::Generator(..) => Tuple(vec![]), // FIXME(pcwalton) ty::Bound(..) => panic!("Bound"), + ty::Placeholder(..) => panic!("Placeholder"), ty::UnnormalizedProjection(..) => panic!("UnnormalizedProjection"), ty::GeneratorWitness(..) => panic!("GeneratorWitness"), ty::Infer(..) => panic!("Infer"), diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 471ba6345e248..f3ded2a5376a6 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -527,7 +527,7 @@ fn resolution_failure( doc_comment_padding + // Each subsequent leading whitespace and `///` code_dox.lines().skip(1).take(line_offset - 1).fold(0, |sum, line| { - sum + doc_comment_padding + line.len() - line.trim().len() + sum + doc_comment_padding + line.len() - line.trim_start().len() }) }; diff --git a/src/libserialize/hex.rs b/src/libserialize/hex.rs index 7f3736e82caa6..5604729d2f8dc 100644 --- a/src/libserialize/hex.rs +++ b/src/libserialize/hex.rs @@ -146,7 +146,7 @@ impl FromHex for str { } match modulus { - 0 => Ok(b.into_iter().collect()), + 0 => Ok(b), _ => Err(InvalidHexLength), } } diff --git a/src/libstd/sys/cloudabi/time.rs b/src/libstd/sys/cloudabi/time.rs index 3d66998b9f549..a442d1e4ad7b7 100644 --- a/src/libstd/sys/cloudabi/time.rs +++ b/src/libstd/sys/cloudabi/time.rs @@ -19,10 +19,14 @@ pub struct Instant { t: abi::timestamp, } -pub fn dur2intervals(dur: &Duration) -> abi::timestamp { +fn checked_dur2intervals(dur: &Duration) -> Option { dur.as_secs() .checked_mul(NSEC_PER_SEC) .and_then(|nanos| nanos.checked_add(dur.subsec_nanos() as abi::timestamp)) +} + +pub fn dur2intervals(dur: &Duration) -> abi::timestamp { + checked_dur2intervals(dur) .expect("overflow converting duration to nanoseconds") } @@ -92,11 +96,14 @@ impl SystemTime { } pub fn add_duration(&self, other: &Duration) -> SystemTime { - SystemTime { - t: self.t - .checked_add(dur2intervals(other)) - .expect("overflow when adding duration to instant"), - } + self.checked_add_duration(other) + .expect("overflow when adding duration to instant") + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option { + checked_dur2intervals(other) + .and_then(|d| self.t.checked_add(d)) + .map(|t| SystemTime {t}) } pub fn sub_duration(&self, other: &Duration) -> SystemTime { diff --git a/src/libstd/sys/redox/time.rs b/src/libstd/sys/redox/time.rs index aac6d2704e790..8a4e63acf8317 100644 --- a/src/libstd/sys/redox/time.rs +++ b/src/libstd/sys/redox/time.rs @@ -42,27 +42,36 @@ impl Timespec { } fn add_duration(&self, other: &Duration) -> Timespec { - let mut secs = other + self.checked_add_duration(other).expect("overflow when adding duration to time") + } + + fn checked_add_duration(&self, other: &Duration) -> Option { + let mut secs = match other .as_secs() .try_into() // <- target type would be `i64` .ok() .and_then(|secs| self.t.tv_sec.checked_add(secs)) - .expect("overflow when adding duration to time"); + { + Some(ts) => ts, + None => return None, + }; // Nano calculations can't overflow because nanos are <1B which fit // in a u32. let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32; if nsec >= NSEC_PER_SEC as u32 { nsec -= NSEC_PER_SEC as u32; - secs = secs.checked_add(1).expect("overflow when adding \ - duration to time"); + secs = match secs.checked_add(1) { + Some(ts) => ts, + None => return None, + } } - Timespec { + Some(Timespec { t: syscall::TimeSpec { tv_sec: secs, tv_nsec: nsec as i32, }, - } + }) } fn sub_duration(&self, other: &Duration) -> Timespec { @@ -180,6 +189,10 @@ impl SystemTime { SystemTime { t: self.t.add_duration(other) } } + pub fn checked_add_duration(&self, other: &Duration) -> Option { + self.t.add_duration(other).map(|t| SystemTime { t }) + } + pub fn sub_duration(&self, other: &Duration) -> SystemTime { SystemTime { t: self.t.sub_duration(other) } } diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index af51f8a8e257a..76f949ce78ff4 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -43,27 +43,36 @@ impl Timespec { } fn add_duration(&self, other: &Duration) -> Timespec { - let mut secs = other + self.checked_add_duration(other).expect("overflow when adding duration to time") + } + + fn checked_add_duration(&self, other: &Duration) -> Option { + let mut secs = match other .as_secs() .try_into() // <- target type would be `libc::time_t` .ok() .and_then(|secs| self.t.tv_sec.checked_add(secs)) - .expect("overflow when adding duration to time"); + { + Some(ts) => ts, + None => return None, + }; // Nano calculations can't overflow because nanos are <1B which fit // in a u32. let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32; if nsec >= NSEC_PER_SEC as u32 { nsec -= NSEC_PER_SEC as u32; - secs = secs.checked_add(1).expect("overflow when adding \ - duration to time"); + secs = match secs.checked_add(1) { + Some(ts) => ts, + None => return None, + } } - Timespec { + Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _, }, - } + }) } fn sub_duration(&self, other: &Duration) -> Timespec { @@ -201,6 +210,10 @@ mod inner { SystemTime { t: self.t.add_duration(other) } } + pub fn checked_add_duration(&self, other: &Duration) -> Option { + self.t.checked_add_duration(other).map(|t| SystemTime { t }) + } + pub fn sub_duration(&self, other: &Duration) -> SystemTime { SystemTime { t: self.t.sub_duration(other) } } @@ -325,6 +338,10 @@ mod inner { SystemTime { t: self.t.add_duration(other) } } + pub fn checked_add_duration(&self, other: &Duration) -> Option { + self.t.checked_add_duration(other).map(|t| SystemTime { t }) + } + pub fn sub_duration(&self, other: &Duration) -> SystemTime { SystemTime { t: self.t.sub_duration(other) } } diff --git a/src/libstd/sys/wasm/time.rs b/src/libstd/sys/wasm/time.rs index e52435e63398f..991e8176edf6d 100644 --- a/src/libstd/sys/wasm/time.rs +++ b/src/libstd/sys/wasm/time.rs @@ -51,6 +51,10 @@ impl SystemTime { SystemTime(self.0 + *other) } + pub fn checked_add_duration(&self, other: &Duration) -> Option { + self.0.checked_add(*other).map(|d| SystemTime(d)) + } + pub fn sub_duration(&self, other: &Duration) -> SystemTime { SystemTime(self.0 - *other) } diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs index 54bcbc76b1a3c..c809a0b98ac94 100644 --- a/src/libstd/sys/windows/time.rs +++ b/src/libstd/sys/windows/time.rs @@ -128,9 +128,13 @@ impl SystemTime { } pub fn add_duration(&self, other: &Duration) -> SystemTime { - let intervals = self.intervals().checked_add(dur2intervals(other)) - .expect("overflow when adding duration to time"); - SystemTime::from_intervals(intervals) + self.checked_add_duration(other).expect("overflow when adding duration to time") + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option { + checked_dur2intervals(other) + .and_then(|d| self.intervals().checked_add(d)) + .map(|i| SystemTime::from_intervals(i)) } pub fn sub_duration(&self, other: &Duration) -> SystemTime { @@ -180,11 +184,15 @@ impl Hash for SystemTime { } } -fn dur2intervals(d: &Duration) -> i64 { +fn checked_dur2intervals(d: &Duration) -> Option { d.as_secs() .checked_mul(INTERVALS_PER_SEC) .and_then(|i| i.checked_add(d.subsec_nanos() as u64 / 100)) .and_then(|i| i.try_into().ok()) +} + +fn dur2intervals(d: &Duration) -> i64 { + checked_dur2intervals(d) .expect("overflow when converting duration to intervals") } diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 90ab349159915..c905af442de1a 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -357,6 +357,14 @@ impl SystemTime { pub fn elapsed(&self) -> Result { SystemTime::now().duration_since(*self) } + + /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as + /// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None` + /// otherwise. + #[unstable(feature = "time_checked_add", issue = "55940")] + pub fn checked_add(&self, duration: Duration) -> Option { + self.0.checked_add_duration(&duration).map(|t| SystemTime(t)) + } } #[stable(feature = "time2", since = "1.8.0")] @@ -557,6 +565,19 @@ mod tests { let one_second_from_epoch2 = UNIX_EPOCH + Duration::new(0, 500_000_000) + Duration::new(0, 500_000_000); assert_eq!(one_second_from_epoch, one_second_from_epoch2); + + // checked_add_duration will not panic on overflow + let mut maybe_t = Some(SystemTime::UNIX_EPOCH); + let max_duration = Duration::from_secs(u64::max_value()); + // in case `SystemTime` can store `>= UNIX_EPOCH + max_duration`. + for _ in 0..2 { + maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration)); + } + assert_eq!(maybe_t, None); + + // checked_add_duration calculates the right time and will work for another year + let year = Duration::from_secs(60 * 60 * 24 * 365); + assert_eq!(a + year, a.checked_add(year).unwrap()); } #[test] diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 2f6b306e8f8ba..a5b12ce4c4d83 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -1200,16 +1200,14 @@ impl<'a> MethodDef<'a> { let sp = trait_.span; let variants = &enum_def.variants; - let self_arg_names = self_args.iter() - .enumerate() - .map(|(arg_count, _self_arg)| { - if arg_count == 0 { - "__self".to_string() - } else { + let self_arg_names = iter::once("__self".to_string()).chain( + self_args.iter() + .enumerate() + .skip(1) + .map(|(arg_count, _self_arg)| format!("__arg_{}", arg_count) - } - }) - .collect::>(); + ) + ).collect::>(); let self_arg_idents = self_arg_names.iter() .map(|name| cx.ident_of(&name[..])) @@ -1218,7 +1216,7 @@ impl<'a> MethodDef<'a> { // The `vi_idents` will be bound, solely in the catch-all, to // a series of let statements mapping each self_arg to an int // value corresponding to its discriminant. - let vi_idents: Vec = self_arg_names.iter() + let vi_idents = self_arg_names.iter() .map(|name| { let vi_suffix = format!("{}_vi", &name[..]); cx.ident_of(&vi_suffix[..]).gensym() diff --git a/src/test/codegen/union-abi.rs b/src/test/codegen/union-abi.rs new file mode 100644 index 0000000000000..786968128ec1b --- /dev/null +++ b/src/test/codegen/union-abi.rs @@ -0,0 +1,80 @@ +// Copyright 2017 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-flags: -C no-prepopulate-passes + +// This test that using union forward the abi of the inner type, as +// discussed in #54668 + +#![crate_type="lib"] +#![feature(repr_simd)] + +#[derive(Copy, Clone)] +pub enum Unhab {} + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct i64x4(i64, i64, i64, i64); + +#[derive(Copy, Clone)] +pub union UnionI64x4{ a:(), b: i64x4 } + +// CHECK: define void @test_UnionI64x4(<4 x i64>* {{.*}} %arg0) +#[no_mangle] +pub fn test_UnionI64x4(_: UnionI64x4) { loop {} } + +pub union UnionI64x4_{ a: i64x4, b: (), c:i64x4, d: Unhab, e: ((),()), f: UnionI64x4 } + +// CHECK: define void @test_UnionI64x4_(<4 x i64>* {{.*}} %arg0) +#[no_mangle] +pub fn test_UnionI64x4_(_: UnionI64x4_) { loop {} } + +pub union UnionI64x4I64{ a: i64x4, b: i64 } + +// CHECK: define void @test_UnionI64x4I64(%UnionI64x4I64* {{.*}} %arg0) +#[no_mangle] +pub fn test_UnionI64x4I64(_: UnionI64x4I64) { loop {} } + +pub union UnionI64x4Tuple{ a: i64x4, b: (i64, i64, i64, i64) } + +// CHECK: define void @test_UnionI64x4Tuple(%UnionI64x4Tuple* {{.*}} %arg0) +#[no_mangle] +pub fn test_UnionI64x4Tuple(_: UnionI64x4Tuple) { loop {} } + + +pub union UnionF32{a:f32} + +// CHECK: define float @test_UnionF32(float %arg0) +#[no_mangle] +pub fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} } + +pub union UnionF32F32{a:f32, b:f32} + +// CHECK: define float @test_UnionF32F32(float %arg0) +#[no_mangle] +pub fn test_UnionF32F32(_: UnionF32F32) -> UnionF32F32 { loop {} } + +pub union UnionF32U32{a:f32, b:u32} + +// CHECK: define i32 @test_UnionF32U32(i32) +#[no_mangle] +pub fn test_UnionF32U32(_: UnionF32U32) -> UnionF32U32 { loop {} } + +pub union UnionU128{a:u128} +// CHECK: define i128 @test_UnionU128(i128 %arg0) +#[no_mangle] +pub fn test_UnionU128(_: UnionU128) -> UnionU128 { loop {} } + +#[repr(C)] +pub union CUnionU128{a:u128} +// CHECK: define void @test_CUnionU128(%CUnionU128* {{.*}} %arg0) +#[no_mangle] +pub fn test_CUnionU128(_: CUnionU128) { loop {} } + diff --git a/src/test/run-pass-fulldeps/auxiliary/linkage-visibility.rs b/src/test/run-pass-fulldeps/auxiliary/linkage-visibility.rs index 4ea3d0d0d0a07..2aaa28341ad91 100644 --- a/src/test/run-pass-fulldeps/auxiliary/linkage-visibility.rs +++ b/src/test/run-pass-fulldeps/auxiliary/linkage-visibility.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-musl - dlsym doesn't see symbols without "-C link-arg=-Wl,--export-dynamic" + #![feature(rustc_private)] // We're testing linkage visibility; the compiler warns us, but we want to diff --git a/src/test/run-pass/mpsc_stress.rs b/src/test/run-pass/mpsc_stress.rs new file mode 100644 index 0000000000000..aa369bb17fead --- /dev/null +++ b/src/test/run-pass/mpsc_stress.rs @@ -0,0 +1,172 @@ +// Copyright 2017 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-flags:--test +// ignore-emscripten + +use std::sync::mpsc::channel; +use std::sync::mpsc::TryRecvError; +use std::sync::mpsc::RecvError; +use std::sync::mpsc::RecvTimeoutError; +use std::sync::Arc; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; + +use std::thread; +use std::time::Duration; + + +/// Simple thread synchronization utility +struct Barrier { + // Not using mutex/condvar for precision + shared: Arc, + count: usize, +} + +impl Barrier { + fn new(count: usize) -> Vec { + let shared = Arc::new(AtomicUsize::new(0)); + (0..count).map(|_| Barrier { shared: shared.clone(), count: count }).collect() + } + + fn new2() -> (Barrier, Barrier) { + let mut v = Barrier::new(2); + (v.pop().unwrap(), v.pop().unwrap()) + } + + /// Returns when `count` threads enter `wait` + fn wait(self) { + self.shared.fetch_add(1, Ordering::SeqCst); + while self.shared.load(Ordering::SeqCst) != self.count { + } + } +} + + +fn shared_close_sender_does_not_lose_messages_iter() { + let (tb, rb) = Barrier::new2(); + + let (tx, rx) = channel(); + let _ = tx.clone(); // convert to shared + + thread::spawn(move || { + tb.wait(); + thread::sleep(Duration::from_micros(1)); + tx.send(17).expect("send"); + drop(tx); + }); + + let i = rx.into_iter(); + rb.wait(); + // Make sure it doesn't return disconnected before returning an element + assert_eq!(vec![17], i.collect::>()); +} + +#[test] +fn shared_close_sender_does_not_lose_messages() { + for _ in 0..10000 { + shared_close_sender_does_not_lose_messages_iter(); + } +} + + +// https://github.com/rust-lang/rust/issues/39364 +fn concurrent_recv_timeout_and_upgrade_iter() { + // 1 us + let sleep = Duration::new(0, 1_000); + + let (a, b) = Barrier::new2(); + let (tx, rx) = channel(); + let th = thread::spawn(move || { + a.wait(); + loop { + match rx.recv_timeout(sleep) { + Ok(_) => { + break; + }, + Err(_) => {}, + } + } + }); + b.wait(); + thread::sleep(sleep); + tx.clone().send(()).expect("send"); + th.join().unwrap(); +} + +#[test] +fn concurrent_recv_timeout_and_upgrade() { + // FIXME: fix and enable + if true { return } + + // at the moment of writing this test fails like this: + // thread '' panicked at 'assertion failed: `(left == right)` + // left: `4561387584`, + // right: `0`', libstd/sync/mpsc/shared.rs:253:13 + + for _ in 0..10000 { + concurrent_recv_timeout_and_upgrade_iter(); + } +} + + +fn concurrent_writes_iter() { + const THREADS: usize = 4; + const PER_THR: usize = 100; + + let mut bs = Barrier::new(THREADS + 1); + let (tx, rx) = channel(); + + let mut threads = Vec::new(); + for j in 0..THREADS { + let tx = tx.clone(); + let b = bs.pop().unwrap(); + threads.push(thread::spawn(move || { + b.wait(); + for i in 0..PER_THR { + tx.send(j * 1000 + i).expect("send"); + } + })); + } + + let b = bs.pop().unwrap(); + b.wait(); + + let mut v: Vec<_> = rx.iter().take(THREADS * PER_THR).collect(); + v.sort(); + + for j in 0..THREADS { + for i in 0..PER_THR { + assert_eq!(j * 1000 + i, v[j * PER_THR + i]); + } + } + + for t in threads { + t.join().unwrap(); + } + + let one_us = Duration::new(0, 1000); + + assert_eq!(TryRecvError::Empty, rx.try_recv().unwrap_err()); + assert_eq!(RecvTimeoutError::Timeout, rx.recv_timeout(one_us).unwrap_err()); + + drop(tx); + + assert_eq!(RecvError, rx.recv().unwrap_err()); + assert_eq!(RecvTimeoutError::Disconnected, rx.recv_timeout(one_us).unwrap_err()); + assert_eq!(TryRecvError::Disconnected, rx.try_recv().unwrap_err()); +} + +#[test] +fn concurrent_writes() { + for _ in 0..100 { + concurrent_writes_iter(); + } +} diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.rs b/src/test/rustdoc-ui/intra-link-span-ice-55723.rs new file mode 100644 index 0000000000000..12e59a4813f85 --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-span-ice-55723.rs @@ -0,0 +1,24 @@ +// 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. + +// ignore-tidy-end-whitespace + +#![deny(intra_doc_link_resolution_failure)] + +// An error in calculating spans while reporting intra-doc link resolution errors caused rustdoc to +// attempt to slice in the middle of a multibyte character. See +// https://github.com/rust-lang/rust/issues/55723 + +/// ## For example: +/// +/// (arr[i]) +pub fn test_ice() { + unimplemented!(); +} diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr new file mode 100644 index 0000000000000..7ae6af4a75e8c --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr @@ -0,0 +1,13 @@ +error: `[i]` cannot be resolved, ignoring it... + --> $DIR/intra-link-span-ice-55723.rs:21:10 + | +LL | /// (arr[i]) + | ^ cannot be resolved, ignoring + | +note: lint level defined here + --> $DIR/intra-link-span-ice-55723.rs:13:9 + | +LL | #![deny(intra_doc_link_resolution_failure)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]` + diff --git a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr index cc1db5db6915c..0126743eedecb 100644 --- a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr +++ b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:24:5 | LL | const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior @@ -36,7 +36,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:36:5 | LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior @@ -74,7 +74,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:51:5 | LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior @@ -96,7 +96,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:60:5 | LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior @@ -144,7 +144,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:78:5 | LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior @@ -184,7 +184,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:93:5 | LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior @@ -208,7 +208,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:102:5 | LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior diff --git a/src/test/ui/consts/const-eval/issue-52442.stderr b/src/test/ui/consts/const-eval/issue-52442.stderr index 3075be9e28b35..608094b179dd6 100644 --- a/src/test/ui/consts/const-eval/issue-52442.stderr +++ b/src/test/ui/consts/const-eval/issue-52442.stderr @@ -8,7 +8,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/issue-52442.rs:12:11 | LL | [(); { &loop { break } as *const _ as usize } ]; //~ ERROR unimplemented expression type - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior diff --git a/src/test/ui/consts/const-eval/issue-55541.rs b/src/test/ui/consts/const-eval/issue-55541.rs new file mode 100644 index 0000000000000..611fb89341de4 --- /dev/null +++ b/src/test/ui/consts/const-eval/issue-55541.rs @@ -0,0 +1,27 @@ +// compile-pass + +// Test that we can handle newtypes wrapping extern types + +#![feature(extern_types, const_transmute)] + +use std::marker::PhantomData; + +extern "C" { + pub type ExternType; +} +unsafe impl Sync for ExternType {} +static MAGIC_FFI_STATIC: u8 = 42; + +#[repr(transparent)] +pub struct Wrapper(ExternType); +pub static MAGIC_FFI_REF: &'static Wrapper = unsafe { + std::mem::transmute(&MAGIC_FFI_STATIC) +}; + +#[repr(transparent)] +pub struct Wrapper2(PhantomData>, ExternType); +pub static MAGIC_FFI_REF2: &'static Wrapper2 = unsafe { + std::mem::transmute(&MAGIC_FFI_STATIC) +}; + +fn main() {} diff --git a/src/test/ui/consts/const-eval/ref_to_int_match.stderr b/src/test/ui/consts/const-eval/ref_to_int_match.stderr index d55c1c2c70ba1..c4bad73eb0276 100644 --- a/src/test/ui/consts/const-eval/ref_to_int_match.stderr +++ b/src/test/ui/consts/const-eval/ref_to_int_match.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ref_to_int_match.rs:33:1 | LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; //~ ERROR it is undefined behavior to use this value - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior diff --git a/src/test/ui/consts/const-eval/ub-enum.rs b/src/test/ui/consts/const-eval/ub-enum.rs index 0aa15c8393879..89b449464419e 100644 --- a/src/test/ui/consts/const-eval/ub-enum.rs +++ b/src/test/ui/consts/const-eval/ub-enum.rs @@ -39,6 +39,7 @@ union TransmuteEnum2 { in3: (), out1: Enum2, out2: Wrap, // something wrapping the enum so that we test layout first, not enum + out3: Option, } const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 }; //~^ ERROR is undefined behavior @@ -51,6 +52,10 @@ const BAD_ENUM4: Wrap = unsafe { TransmuteEnum2 { in2: &0 }.out2 }; const BAD_ENUM_UNDEF: [Enum2; 2] = [unsafe { TransmuteEnum2 { in3: () }.out1 }; 2]; //~^ ERROR is undefined behavior +// Pointer value in an enum with a niche that is not just 0. +const BAD_ENUM_PTR: Option = unsafe { TransmuteEnum2 { in2: &0 }.out3 }; +//~^ ERROR is undefined behavior + // Invalid enum field content (mostly to test printing of paths for enum tuple // variants and tuples). union TransmuteChar { diff --git a/src/test/ui/consts/const-eval/ub-enum.stderr b/src/test/ui/consts/const-eval/ub-enum.stderr index d36e96b08174a..5aae3a2f35110 100644 --- a/src/test/ui/consts/const-eval/ub-enum.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.stderr @@ -7,7 +7,7 @@ LL | const BAD_ENUM: Enum = unsafe { TransmuteEnum { a: &1 }.out }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:43:1 + --> $DIR/ub-enum.rs:44:1 | LL | const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected a valid enum discriminant @@ -15,7 +15,7 @@ LL | const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:45:1 + --> $DIR/ub-enum.rs:46:1 | LL | const BAD_ENUM3: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant @@ -23,7 +23,7 @@ LL | const BAD_ENUM3: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:47:1 + --> $DIR/ub-enum.rs:48:1 | LL | const BAD_ENUM4: Wrap = unsafe { TransmuteEnum2 { in2: &0 }.out2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected something that cannot possibly fail to be in the range 2..=2 @@ -31,21 +31,29 @@ LL | const BAD_ENUM4: Wrap = unsafe { TransmuteEnum2 { in2: &0 }.out2 }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:51:1 + --> $DIR/ub-enum.rs:52:1 | LL | const BAD_ENUM_UNDEF: [Enum2; 2] = [unsafe { TransmuteEnum2 { in3: () }.out1 }; 2]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to read undefined bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at [0], but expected a valid enum discriminant | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:61:1 + --> $DIR/ub-enum.rs:56:1 + | +LL | const BAD_ENUM_PTR: Option = unsafe { TransmuteEnum2 { in2: &0 }.out3 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:66:1 | LL | const BAD_ENUM_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at ..0.1, but expected something less or equal to 1114111 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/ub-ref.stderr b/src/test/ui/consts/const-eval/ub-ref.stderr index c3f5f4a26f555..fe969d40a2ea6 100644 --- a/src/test/ui/consts/const-eval/ub-ref.stderr +++ b/src/test/ui/consts/const-eval/ub-ref.stderr @@ -18,7 +18,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref.rs:22:1 | LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior @@ -26,7 +26,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref.rs:25:1 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected plain bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior diff --git a/src/test/ui/consts/const-eval/union-ice.stderr b/src/test/ui/consts/const-eval/union-ice.stderr index d5a20640771df..98c2c1472aae0 100644 --- a/src/test/ui/consts/const-eval/union-ice.stderr +++ b/src/test/ui/consts/const-eval/union-ice.stderr @@ -13,7 +13,7 @@ LL | / const FIELD_PATH: Struct = Struct { //~ ERROR it is undefined behavior to LL | | a: 42, LL | | b: unsafe { UNION.field3 }, LL | | }; - | |__^ type validation failed: encountered uninitialized bytes at .b, but expected initialized plain bits + | |__^ type validation failed: encountered uninitialized bytes at .b, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior diff --git a/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr b/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr index 03de0efd07362..a4c228416147e 100644 --- a/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr +++ b/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr @@ -10,7 +10,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/issue-52023-array-size-pointer-cast.rs:12:17 | LL | let _ = [0; (&0 as *const i32) as usize]; //~ ERROR casting pointers to integers in constants - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior diff --git a/src/test/ui/nll/user-annotations/dump-fn-method.stderr b/src/test/ui/nll/user-annotations/dump-fn-method.stderr index 359423d0cfbea..c963625c961e8 100644 --- a/src/test/ui/nll/user-annotations/dump-fn-method.stderr +++ b/src/test/ui/nll/user-annotations/dump-fn-method.stderr @@ -4,7 +4,7 @@ error: user substs: Canonical { max_universe: U0, variables: [], value: UserSubs LL | let x = foo::; //~ ERROR [u32] | ^^^^^^^^^^ -error: user substs: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: UserSubsts { substs: [^0, u32, ^1], user_self_ty: None } } +error: user substs: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }], value: UserSubsts { substs: [^0, u32, ^1], user_self_ty: None } } --> $DIR/dump-fn-method.rs:42:13 | LL | let x = <_ as Bazoom>::method::<_>; //~ ERROR [^0, u32, ^1] @@ -16,7 +16,7 @@ error: user substs: Canonical { max_universe: U0, variables: [], value: UserSubs LL | let x = >::method::; //~ ERROR [u8, u16, u32] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: user substs: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: UserSubsts { substs: [^0, ^1, u32], user_self_ty: None } } +error: user substs: Canonical { max_universe: U1, variables: [CanonicalVarInfo { kind: Ty(General(U1)) }, CanonicalVarInfo { kind: Ty(General(U1)) }], value: UserSubsts { substs: [^0, ^1, u32], user_self_ty: None } } --> $DIR/dump-fn-method.rs:54:5 | LL | y.method::(44, 66); //~ ERROR [^0, ^1, u32]