diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2017-05-19 17:27:25 -0400 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2017-06-01 12:56:30 -0400 |
| commit | 541523d10dce98dc266f6d4e6fb6131182c0f791 (patch) | |
| tree | 8a9f72b4e0c7d4e1ec48d65440016fac921337a0 | |
| parent | 6c4b961effdbec1bb2fc5aaed5aeb219eb7f3b19 (diff) | |
rewrite layout to take a (param-env, ty) pair instead of infcx
| -rw-r--r-- | src/librustc/dep_graph/dep_node.rs | 2 | ||||
| -rw-r--r-- | src/librustc/middle/intrinsicck.rs | 51 | ||||
| -rw-r--r-- | src/librustc/ty/layout.rs | 236 | ||||
| -rw-r--r-- | src/librustc/ty/maps.rs | 15 | ||||
| -rw-r--r-- | src/librustc/ty/util.rs | 52 | ||||
| -rw-r--r-- | src/librustc_lint/types.rs | 13 | ||||
| -rw-r--r-- | src/librustc_mir/transform/inline.rs | 6 | ||||
| -rw-r--r-- | src/librustc_trans/context.rs | 46 | ||||
| -rw-r--r-- | src/librustc_trans/glue.rs | 16 |
9 files changed, 225 insertions, 212 deletions
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 38ad473e404..c38b3745f4c 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -112,6 +112,7 @@ pub enum DepNode<D: Clone + Debug> { IsSized(D), IsFreeze(D), NeedsDrop(D), + Layout(D), // The set of impls for a given trait. Ultimately, it would be // nice to get more fine-grained here (e.g., to include a @@ -241,6 +242,7 @@ impl<D: Clone + Debug> DepNode<D> { IsSized(ref d) => op(d).map(IsSized), IsFreeze(ref d) => op(d).map(IsFreeze), NeedsDrop(ref d) => op(d).map(NeedsDrop), + Layout(ref d) => op(d).map(Layout), Hir(ref d) => op(d).map(Hir), HirBody(ref d) => op(d).map(HirBody), MetaData(ref d) => op(d).map(MetaData), diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 08f731ae34d..57815b7f0b6 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -10,7 +10,6 @@ use hir::def::Def; use hir::def_id::DefId; -use infer::InferCtxt; use ty::{self, Ty, TyCtxt}; use ty::layout::{LayoutError, Pointer, SizeSkeleton}; @@ -30,8 +29,10 @@ struct ItemVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> } -struct ExprVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - infcx: &'a InferCtxt<'a, 'gcx, 'tcx> +struct ExprVisitor<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + tables: &'tcx ty::TypeckTables<'tcx>, + param_env: ty::ParamEnv<'tcx>, } /// If the type is `Option<T>`, it will return `T`, otherwise @@ -63,18 +64,18 @@ fn unpack_option_like<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty } -impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> ExprVisitor<'a, 'tcx> { fn def_id_is_transmute(&self, def_id: DefId) -> bool { - let intrinsic = match self.infcx.tcx.type_of(def_id).sty { + let intrinsic = match self.tcx.type_of(def_id).sty { ty::TyFnDef(.., bfty) => bfty.abi() == RustIntrinsic, _ => return false }; - intrinsic && self.infcx.tcx.item_name(def_id) == "transmute" + intrinsic && self.tcx.item_name(def_id) == "transmute" } - fn check_transmute(&self, span: Span, from: Ty<'gcx>, to: Ty<'gcx>) { - let sk_from = SizeSkeleton::compute(from, self.infcx); - let sk_to = SizeSkeleton::compute(to, self.infcx); + fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>) { + let sk_from = SizeSkeleton::compute(from, self.tcx, self.param_env); + let sk_to = SizeSkeleton::compute(to, self.tcx, self.param_env); // Check for same size using the skeletons. if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) { @@ -84,11 +85,11 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> { // Special-case transmutting from `typeof(function)` and // `Option<typeof(function)>` to present a clearer error. - let from = unpack_option_like(self.infcx.tcx.global_tcx(), from); + let from = unpack_option_like(self.tcx.global_tcx(), from); match (&from.sty, sk_to) { (&ty::TyFnDef(..), SizeSkeleton::Known(size_to)) - if size_to == Pointer.size(self.infcx) => { - struct_span_err!(self.infcx.tcx.sess, span, E0591, + if size_to == Pointer.size(self.tcx) => { + struct_span_err!(self.tcx.sess, span, E0591, "`{}` is zero-sized and can't be transmuted to `{}`", from, to) .span_note(span, "cast with `as` to a pointer instead") @@ -100,7 +101,7 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> { } // Try to display a sensible error with as much information as possible. - let skeleton_string = |ty: Ty<'gcx>, sk| { + let skeleton_string = |ty: Ty<'tcx>, sk| { match sk { Ok(SizeSkeleton::Known(size)) => { format!("{} bits", size.bits()) @@ -119,7 +120,7 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> { } }; - struct_span_err!(self.infcx.tcx.sess, span, E0512, + struct_span_err!(self.tcx.sess, span, E0512, "transmute called with differently sized types: \ {} ({}) to {} ({})", from, skeleton_string(from, sk_from), @@ -138,32 +139,30 @@ impl<'a, 'tcx> Visitor<'tcx> for ItemVisitor<'a, 'tcx> { } fn visit_nested_body(&mut self, body_id: hir::BodyId) { + let owner_def_id = self.tcx.hir.body_owner_def_id(body_id); let body = self.tcx.hir.body(body_id); - self.tcx.infer_ctxt(body_id).enter(|infcx| { - let mut visitor = ExprVisitor { - infcx: &infcx - }; - visitor.visit_body(body); - }); + let param_env = self.tcx.param_env(owner_def_id); + let tables = self.tcx.typeck_tables_of(owner_def_id); + ExprVisitor { tcx: self.tcx, param_env, tables }.visit_body(body); self.visit_body(body); } } -impl<'a, 'gcx, 'tcx> Visitor<'gcx> for ExprVisitor<'a, 'gcx, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> { +impl<'a, 'tcx> Visitor<'tcx> for ExprVisitor<'a, 'tcx> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { NestedVisitorMap::None } - fn visit_expr(&mut self, expr: &'gcx hir::Expr) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr) { let def = if let hir::ExprPath(ref qpath) = expr.node { - self.infcx.tables.borrow().qpath_def(qpath, expr.id) + self.tables.qpath_def(qpath, expr.id) } else { Def::Err }; match def { Def::Fn(did) if self.def_id_is_transmute(did) => { - let typ = self.infcx.tables.borrow().node_id_to_type(expr.id); - let typ = self.infcx.tcx.lift_to_global(&typ).unwrap(); + let typ = self.tables.node_id_to_type(expr.id); + let typ = self.tcx.lift_to_global(&typ).unwrap(); match typ.sty { ty::TyFnDef(.., sig) if sig.abi() == RustIntrinsic => { let from = sig.inputs().skip_binder()[0]; diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 1a8c74ff1f9..4dc764f6d30 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -12,9 +12,7 @@ pub use self::Integer::*; pub use self::Layout::*; pub use self::Primitive::*; -use infer::InferCtxt; use session::Session; -use traits; use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions, ReprFlags}; use syntax::ast::{FloatTy, IntTy, UintTy}; @@ -212,6 +210,12 @@ impl<'a> HasDataLayout for &'a TargetDataLayout { } } +impl<'a, 'tcx> HasDataLayout for TyCtxt<'a, 'tcx, 'tcx> { + fn data_layout(&self) -> &TargetDataLayout { + &self.data_layout + } +} + /// Endianness of the target, which must match cfg(target-endian). #[derive(Copy, Clone)] pub enum Endian { @@ -457,8 +461,12 @@ impl Integer { /// signed discriminant range and #[repr] attribute. /// N.B.: u64 values above i64::MAX will be treated as signed, but /// that shouldn't affect anything, other than maybe debuginfo. - fn repr_discr(tcx: TyCtxt, ty: Ty, repr: &ReprOptions, min: i64, max: i64) - -> (Integer, bool) { + fn repr_discr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + ty: Ty<'tcx>, + repr: &ReprOptions, + min: i64, + max: i64) + -> (Integer, bool) { // Theoretically, negative values could be larger in unsigned representation // than the unsigned representation of the signed minimum. However, if there // are any negative values, the only valid unsigned representation is u64 @@ -583,10 +591,13 @@ enum StructKind { EnumVariant, } -impl<'a, 'gcx, 'tcx> Struct { - fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>, - repr: &ReprOptions, kind: StructKind, - scapegoat: Ty<'gcx>) -> Result<Struct, LayoutError<'gcx>> { +impl<'a, 'tcx> Struct { + fn new(dl: &TargetDataLayout, + fields: &Vec<&'a Layout>, + repr: &ReprOptions, + kind: StructKind, + scapegoat: Ty<'tcx>) + -> Result<Struct, LayoutError<'tcx>> { if repr.packed() && repr.align > 0 { bug!("Struct cannot be packed and aligned"); } @@ -723,8 +734,8 @@ impl<'a, 'gcx, 'tcx> Struct { /// Determine whether a structure would be zero-sized, given its fields. fn would_be_zero_sized<I>(dl: &TargetDataLayout, fields: I) - -> Result<bool, LayoutError<'gcx>> - where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> { + -> Result<bool, LayoutError<'tcx>> + where I: Iterator<Item=Result<&'a Layout, LayoutError<'tcx>>> { for field in fields { let field = field?; if field.is_unsized() || field.size(dl).bytes() > 0 { @@ -764,11 +775,11 @@ impl<'a, 'gcx, 'tcx> Struct { /// The tuple is `(path, source_path)`, /// where `path` is in memory order and `source_path` in source order. // FIXME(eddyb) track value ranges and traverse already optimized enums. - fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'gcx, 'tcx>, - ty: Ty<'gcx>) - -> Result<Option<(FieldPath, FieldPath)>, LayoutError<'gcx>> { - let tcx = infcx.tcx.global_tcx(); - match (ty.layout(infcx)?, &ty.sty) { + fn non_zero_field_in_type(tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>) + -> Result<Option<(FieldPath, FieldPath)>, LayoutError<'tcx>> { + match (ty.layout(tcx, param_env)?, &ty.sty) { (&Scalar { non_zero: true, .. }, _) | (&CEnum { non_zero: true, .. }, _) => Ok(Some((vec![], vec![]))), (&FatPointer { non_zero: true, .. }, _) => { @@ -779,7 +790,7 @@ impl<'a, 'gcx, 'tcx> Struct { (&Univariant { non_zero: true, .. }, &ty::TyAdt(def, substs)) => { let fields = &def.struct_variant().fields; assert_eq!(fields.len(), 1); - match *fields[0].ty(tcx, substs).layout(infcx)? { + match *fields[0].ty(tcx, substs).layout(tcx, param_env)? { // FIXME(eddyb) also allow floating-point types here. Scalar { value: Int(_), non_zero: false } | Scalar { value: Pointer, non_zero: false } => { @@ -796,37 +807,49 @@ impl<'a, 'gcx, 'tcx> Struct { // Perhaps one of the fields of this struct is non-zero // let's recurse and find out (&Univariant { ref variant, .. }, &ty::TyAdt(def, substs)) if def.is_struct() => { - Struct::non_zero_field_paths(infcx, def.struct_variant().fields - .iter().map(|field| { - field.ty(tcx, substs) - }), - Some(&variant.memory_index[..])) + Struct::non_zero_field_paths( + tcx, + param_env, + def.struct_variant().fields.iter().map(|field| { + field.ty(tcx, substs) + }), + Some(&variant.memory_index[..])) } // Perhaps one of the upvars of this closure is non-zero (&Univariant { ref variant, .. }, &ty::TyClosure(def, substs)) => { let upvar_tys = substs.upvar_tys(def, tcx); - Struct::non_zero_field_paths(infcx, upvar_tys, + Struct::non_zero_field_paths( + tcx, + param_env, + upvar_tys, Some(&variant.memory_index[..])) } // Can we use one of the fields in this tuple? (&Univariant { ref variant, .. }, &ty::TyTuple(tys, _)) => { - Struct::non_zero_field_paths(infcx, tys.iter().cloned(), + Struct::non_zero_field_paths( + tcx, + param_env, + tys.iter().cloned(), Some(&variant.memory_index[..])) } // Is this a fixed-size array of something non-zero // with at least one element? (_, &ty::TyArray(ety, d)) if d > 0 => { - Struct::non_zero_field_paths(infcx, Some(ety).into_iter(), None) + Struct::non_zero_field_paths( + tcx, + param_env, + Some(ety).into_iter(), + None) } (_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => { - let normalized = infcx.normalize_projections(ty); + let normalized = tcx.normalize_associated_type_in_env(&ty, param_env); if ty == normalized { return Ok(None); } - return Struct::non_zero_field_in_type(infcx, normalized); + return Struct::non_zero_field_in_type(tcx, param_env, normalized); } // Anything else is not a non-zero type. @@ -838,13 +861,15 @@ impl<'a, 'gcx, 'tcx> Struct { /// the given set of fields and recursing through aggregates. /// Returns Some((path, source_path)) on success. /// `path` is translated to memory order. `source_path` is not. - fn non_zero_field_paths<I>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, - fields: I, - permutation: Option<&[u32]>) - -> Result<Option<(FieldPath, FieldPath)>, LayoutError<'gcx>> - where I: Iterator<Item=Ty<'gcx>> { + fn non_zero_field_paths<I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + fields: I, + permutation: Option<&[u32]>) + -> Result<Option<(FieldPath, FieldPath)>, LayoutError<'tcx>> + where I: Iterator<Item=Ty<'tcx>> { for (i, ty) in fields.enumerate() { - if let Some((mut path, mut source_path)) = Struct::non_zero_field_in_type(infcx, ty)? { + let r = Struct::non_zero_field_in_type(tcx, param_env, ty)?; + if let Some((mut path, mut source_path)) = r { source_path.push(i as u32); let index = if let Some(p) = permutation { p[i] as usize @@ -881,7 +906,7 @@ pub struct Union { pub packed: bool, } -impl<'a, 'gcx, 'tcx> Union { +impl<'a, 'tcx> Union { fn new(dl: &TargetDataLayout, packed: bool) -> Union { let align = if packed { dl.i8_align } else { dl.aggregate_align }; Union { @@ -895,9 +920,9 @@ impl<'a, 'gcx, 'tcx> Union { /// Extend the Struct with more fields. fn extend<I>(&mut self, dl: &TargetDataLayout, fields: I, - scapegoat: Ty<'gcx>) - -> Result<(), LayoutError<'gcx>> - where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> { + scapegoat: Ty<'tcx>) + -> Result<(), LayoutError<'tcx>> + where I: Iterator<Item=Result<&'a Layout, LayoutError<'tcx>>> { for (index, field) in fields.enumerate() { let field = field?; if field.is_unsized() { @@ -1067,19 +1092,19 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> { } } -impl<'a, 'gcx, 'tcx> Layout { - pub fn compute_uncached(ty: Ty<'gcx>, - infcx: &InferCtxt<'a, 'gcx, 'tcx>) - -> Result<&'gcx Layout, LayoutError<'gcx>> { - let tcx = infcx.tcx.global_tcx(); +impl<'a, 'tcx> Layout { + pub fn compute_uncached(tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>) + -> Result<&'tcx Layout, LayoutError<'tcx>> { let success = |layout| Ok(tcx.intern_layout(layout)); let dl = &tcx.data_layout; assert!(!ty.has_infer_types()); - let ptr_layout = |pointee: Ty<'gcx>| { + let ptr_layout = |pointee: Ty<'tcx>| { let non_zero = !ty.is_unsafe_ptr(); - let pointee = infcx.normalize_projections(pointee); - if pointee.is_sized(tcx, infcx.param_env, DUMMY_SP) { + let pointee = tcx.normalize_associated_type_in_env(&pointee, param_env); + if pointee.is_sized(tcx, param_env, DUMMY_SP) { Ok(Scalar { value: Pointer, non_zero: non_zero }) } else { let unsized_part = tcx.struct_tail(pointee); @@ -1132,7 +1157,7 @@ impl<'a, 'gcx, 'tcx> Layout { // Arrays and slices. ty::TyArray(element, count) => { - let element = element.layout(infcx)?; + let element = element.layout(tcx, param_env)?; let element_size = element.size(dl); // FIXME(eddyb) Don't use host `usize` for array lengths. let usize_count: usize = count; @@ -1149,7 +1174,7 @@ impl<'a, 'gcx, 'tcx> Layout { } } ty::TySlice(element) => { - let element = element.layout(infcx)?; + let element = element.layout(tcx, param_env)?; Array { sized: false, align: element.align(dl), @@ -1187,7 +1212,7 @@ impl<'a, 'gcx, 'tcx> Layout { ty::TyClosure(def_id, ref substs) => { let tys = substs.upvar_tys(def_id, tcx); let st = Struct::new(dl, - &tys.map(|ty| ty.layout(infcx)) + &tys.map(|ty| ty.layout(tcx, param_env)) .collect::<Result<Vec<_>, _>>()?, &ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?; @@ -1198,7 +1223,7 @@ impl<'a, 'gcx, 'tcx> Layout { // FIXME(camlorn): if we ever allow unsized tuples, this needs to be checked. // See the univariant case below to learn how. let st = Struct::new(dl, - &tys.iter().map(|ty| ty.layout(infcx)) + &tys.iter().map(|ty| ty.layout(tcx, param_env)) .collect::<Result<Vec<_>, _>>()?, &ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?; Univariant { variant: st, non_zero: false } @@ -1207,7 +1232,7 @@ impl<'a, 'gcx, 'tcx> Layout { // SIMD vector types. ty::TyAdt(def, ..) if def.repr.simd() => { let element = ty.simd_type(tcx); - match *element.layout(infcx)? { + match *element.layout(tcx, param_env)? { Scalar { value, .. } => { return success(Vector { element: value, @@ -1278,7 +1303,7 @@ impl<'a, 'gcx, 'tcx> Layout { }; let fields = def.variants[0].fields.iter().map(|field| { - field.ty(tcx, substs).layout(infcx) + field.ty(tcx, substs).layout(tcx, param_env) }).collect::<Result<Vec<_>, _>>()?; let layout = if def.is_union() { let mut un = Union::new(dl, def.repr.packed()); @@ -1312,20 +1337,21 @@ impl<'a, 'gcx, 'tcx> Layout { // Nullable pointer optimization for discr in 0..2 { let other_fields = variants[1 - discr].iter().map(|ty| { - ty.layout(infcx) + ty.layout(tcx, param_env) }); if !Struct::would_be_zero_sized(dl, other_fields)? { continue; } - let paths = Struct::non_zero_field_paths(infcx, - variants[discr].iter().cloned(), - None)?; + let paths = Struct::non_zero_field_paths(tcx, + param_env, + variants[discr].iter().cloned(), + None)?; let (mut path, mut path_source) = if let Some(p) = paths { p } else { continue }; // FIXME(eddyb) should take advantage of a newtype. if path == &[0] && variants[discr].len() == 1 { - let value = match *variants[discr][0].layout(infcx)? { + let value = match *variants[discr][0].layout(tcx, param_env)? { Scalar { value, .. } => value, CEnum { discr, .. } => Int(discr), _ => bug!("Layout::compute: `{}`'s non-zero \ @@ -1339,7 +1365,7 @@ impl<'a, 'gcx, 'tcx> Layout { } let st = Struct::new(dl, - &variants[discr].iter().map(|ty| ty.layout(infcx)) + &variants[discr].iter().map(|ty| ty.layout(tcx, param_env)) .collect::<Result<Vec<_>, _>>()?, &def.repr, StructKind::AlwaysSizedUnivariant, ty)?; @@ -1377,7 +1403,7 @@ impl<'a, 'gcx, 'tcx> Layout { let discr = Scalar { value: Int(min_ity), non_zero: false }; let mut variants = variants.into_iter().map(|fields| { let mut fields = fields.into_iter().map(|field| { - field.layout(infcx) + field.layout(tcx, param_env) }).collect::<Result<Vec<_>, _>>()?; fields.insert(0, &discr); let st = Struct::new(dl, @@ -1470,11 +1496,11 @@ impl<'a, 'gcx, 'tcx> Layout { // Types with no meaningful known layout. ty::TyProjection(_) | ty::TyAnon(..) => { - let normalized = infcx.normalize_projections(ty); + let normalized = tcx.normalize_associated_type_in_env(&ty, param_env); if ty == normalized { return Err(LayoutError::Unknown(ty)); } - return normalized.layout(infcx); + return normalized.layout(tcx, param_env); } ty::TyParam(_) => { return Err(LayoutError::Unknown(ty)); @@ -1686,21 +1712,22 @@ pub enum SizeSkeleton<'tcx> { } } -impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { - pub fn compute(ty: Ty<'gcx>, infcx: &InferCtxt<'a, 'gcx, 'tcx>) - -> Result<SizeSkeleton<'gcx>, LayoutError<'gcx>> { - let tcx = infcx.tcx.global_tcx(); +impl<'a, 'tcx> SizeSkeleton<'tcx> { + pub fn compute(ty: Ty<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>) + -> Result<SizeSkeleton<'tcx>, LayoutError<'tcx>> { assert!(!ty.has_infer_types()); // First try computing a static layout. - let err = match ty.layout(infcx) { + let err = match ty.layout(tcx, param_env) { Ok(layout) => { return Ok(SizeSkeleton::Known(layout.size(tcx))); } Err(err) => err }; - let ptr_skeleton = |pointee: Ty<'gcx>| { + let ptr_skeleton = |pointee: Ty<'tcx>| { let non_zero = !ty.is_unsafe_ptr(); let tail = tcx.struct_tail(pointee); match tail.sty { @@ -1737,7 +1764,7 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { // Get a zero-sized variant or a pointer newtype. let zero_or_ptr_variant = |i: usize| { let fields = def.variants[i].fields.iter().map(|field| { - SizeSkeleton::compute(field.ty(tcx, substs), infcx) + SizeSkeleton::compute(field.ty(tcx, substs), tcx, param_env) }); let mut ptr = None; for field in fields { @@ -1788,11 +1815,11 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { } ty::TyProjection(_) | ty::TyAnon(..) => { - let normalized = infcx.normalize_projections(ty); + let normalized = tcx.normalize_associated_type_in_env(&ty, param_env); if ty == normalized { Err(err) } else { - SizeSkeleton::compute(normalized, infcx) + SizeSkeleton::compute(normalized, tcx, param_env) } } @@ -1826,71 +1853,53 @@ impl<'tcx> Deref for TyLayout<'tcx> { } } -pub trait HasTyCtxt<'tcx>: HasDataLayout { +pub trait LayoutTyper<'tcx>: HasDataLayout { + type TyLayout; + fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>; + fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout; + fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx>; } -impl<'a, 'gcx, 'tcx> HasDataLayout for TyCtxt<'a, 'gcx, 'tcx> { - fn data_layout(&self) -> &TargetDataLayout { - &self.data_layout - } +/// Combines a tcx with the parameter environment so that you can +/// compute layout operations. +#[derive(Copy, Clone)] +pub struct LayoutCx<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, } -impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for TyCtxt<'a, 'gcx, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> { - self.global_tcx() +impl<'a, 'tcx> LayoutCx<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self { + LayoutCx { tcx, param_env } } } -impl<'a, 'gcx, 'tcx> HasDataLayout for &'a InferCtxt<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> HasDataLayout for LayoutCx<'a, 'tcx> { fn data_layout(&self) -> &TargetDataLayout { &self.tcx.data_layout } } -impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> { - self.tcx.global_tcx() - } -} - -pub trait LayoutTyper<'tcx>: HasTyCtxt<'tcx> { - type TyLayout; - - fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout; - fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx>; -} +impl<'a, 'tcx> LayoutTyper<'tcx> for LayoutCx<'a, 'tcx> { + type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>; -impl<'a, 'gcx, 'tcx> LayoutTyper<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> { - type TyLayout = Result<TyLayout<'gcx>, LayoutError<'gcx>>; + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { + self.tcx + } - fn layout_of(self, ty: Ty<'gcx>) -> Self::TyLayout { + fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { let ty = self.normalize_projections(ty); Ok(TyLayout { ty: ty, - layout: ty.layout(self)?, + layout: ty.layout(self.tcx, self.param_env)?, variant_index: None }) } - fn normalize_projections(self, ty: Ty<'gcx>) -> Ty<'gcx> { - if !ty.has_projection_types() { - return ty; - } - - let mut selcx = traits::SelectionContext::new(self); - let cause = traits::ObligationCause::dummy(); - let traits::Normalized { value: result, obligations } = - traits::normalize(&mut selcx, cause, &ty); - - let mut fulfill_cx = traits::FulfillmentContext::new(); - - for obligation in obligations { - fulfill_cx.register_predicate_obligation(self, obligation); - } - - self.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result) + fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> { + self.tcx.normalize_associated_type_in_env(&ty, self.param_env) } } @@ -1943,7 +1952,7 @@ impl<'a, 'tcx> TyLayout<'tcx> { } } - pub fn field_type<C: HasTyCtxt<'tcx>>(&self, cx: C, i: usize) -> Ty<'tcx> { + pub fn field_type<C: LayoutTyper<'tcx>>(&self, cx: C, i: usize) -> Ty<'tcx> { let tcx = cx.tcx(); let ptr_field_type = |pointee: Ty<'tcx>| { @@ -2014,7 +2023,10 @@ impl<'a, 'tcx> TyLayout<'tcx> { } } - pub fn field<C: LayoutTyper<'tcx>>(&self, cx: C, i: usize) -> C::TyLayout { + pub fn field<C: LayoutTyper<'tcx>>(&self, + cx: C, + i: usize) + -> C::TyLayout { cx.layout_of(cx.normalize_projections(self.field_type(cx, i))) } } diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index da85d40b2c3..b5adcc8ed75 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -20,6 +20,7 @@ use mir::transform::{MirSuite, MirPassIndex}; use session::CompileResult; use traits::specialization_graph; use ty::{self, CrateInherentImpls, Ty, TyCtxt}; +use ty::layout::{Layout, LayoutError}; use ty::item_path; use ty::steal::Steal; use ty::subst::Substs; @@ -293,6 +294,12 @@ impl<'tcx> QueryDescription for queries::needs_drop_raw<'tcx> { } } +impl<'tcx> QueryDescription for queries::layout_raw<'tcx> { + fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { + format!("computing layout of `{}`", env.value) + } +} + impl<'tcx> QueryDescription for queries::super_predicates_of<'tcx> { fn describe(tcx: TyCtxt, def_id: DefId) -> String { format!("computing the supertraits of `{}`", @@ -920,6 +927,8 @@ define_maps! { <'tcx> [] is_sized_raw: is_sized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, [] is_freeze_raw: is_freeze_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, [] needs_drop_raw: needs_drop_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, + [] layout_raw: layout_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) + -> Result<&'tcx Layout, LayoutError<'tcx>>, } fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> { @@ -987,3 +996,9 @@ fn needs_drop_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepNode<De .unwrap_or(DefId::local(CRATE_DEF_INDEX)); DepNode::NeedsDrop(def_id) } + +fn layout_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepNode<DefId> { + let def_id = ty::item_path::characteristic_def_id_of_type(key.value) + .unwrap_or(DefId::local(CRATE_DEF_INDEX)); + DepNode::Layout(def_id) +} diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 31c099c661d..6d55f04e86a 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -12,7 +12,6 @@ use hir::def_id::{DefId, LOCAL_CRATE}; use hir::map::DefPathData; -use infer::InferCtxt; use ich::{StableHashingContext, NodeIdHashingMode}; use traits::{self, Reveal}; use ty::{self, Ty, TyCtxt, TypeFoldable}; @@ -791,35 +790,17 @@ impl<'a, 'tcx> ty::TyS<'tcx> { tcx.needs_drop_raw(param_env.and(self)) } + /// Computes the layout of a type. Note that this implicitly + /// executes in "reveal all" mode. #[inline] - pub fn layout<'lcx>(&'tcx self, infcx: &InferCtxt<'a, 'tcx, 'lcx>) + pub fn layout<'lcx>(&'tcx self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>) -> Result<&'tcx Layout, LayoutError<'tcx>> { - let tcx = infcx.tcx.global_tcx(); - let can_cache = !self.has_param_types() && !self.has_self_ty(); - if can_cache { - if let Some(&cached) = tcx.layout_cache.borrow().get(&self) { - return Ok(cached); - } - } - - let rec_limit = tcx.sess.recursion_limit.get(); - let depth = tcx.layout_depth.get(); - if depth > rec_limit { - tcx.sess.fatal( - &format!("overflow representing the type `{}`", self)); - } - - tcx.layout_depth.set(depth+1); - let layout = Layout::compute_uncached(self, infcx); - tcx.layout_depth.set(depth); - let layout = layout?; - if can_cache { - tcx.layout_cache.borrow_mut().insert(self, layout); - } - Ok(layout) + let ty = tcx.erase_regions(&self); + tcx.layout_raw(param_env.reveal_all().and(ty)) } - /// Check whether a type is representable. This means it cannot contain unboxed /// structural recursion. This check is needed for structs and enums. pub fn is_representable(&'tcx self, @@ -1074,6 +1055,24 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } +fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) + -> Result<&'tcx Layout, LayoutError<'tcx>> +{ + let (param_env, ty) = query.into_parts(); + + let rec_limit = tcx.sess.recursion_limit.get(); + let depth = tcx.layout_depth.get(); + if depth > rec_limit { + tcx.sess.fatal( + &format!("overflow representing the type `{}`", ty)); + } + + tcx.layout_depth.set(depth+1); + let layout = Layout::compute_uncached(tcx, param_env, ty); + tcx.layout_depth.set(depth); + layout +} pub fn provide(providers: &mut ty::maps::Providers) { *providers = ty::maps::Providers { @@ -1081,6 +1080,7 @@ pub fn provide(providers: &mut ty::maps::Providers) { is_sized_raw, is_freeze_raw, needs_drop_raw, + layout_raw, ..*providers }; } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 1b86085d99d..3019165bfbf 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -14,7 +14,6 @@ use rustc::hir::def_id::DefId; use rustc::ty::subst::Substs; use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use rustc::ty::layout::{Layout, Primitive}; -use rustc::traits::Reveal; use middle::const_val::ConstVal; use rustc_const_eval::ConstContext; use util::nodemap::FxHashSet; @@ -724,12 +723,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { if let hir::ItemEnum(ref enum_definition, ref gens) = it.node { if gens.ty_params.is_empty() { // sizes only make sense for non-generic types - let t = cx.tcx.type_of(cx.tcx.hir.local_def_id(it.id)); - let layout = cx.tcx.infer_ctxt(Reveal::All).enter(|infcx| { - let ty = cx.tcx.erase_regions(&t); - ty.layout(&infcx).unwrap_or_else(|e| { - bug!("failed to get layout for `{}`: {}", t, e) - }) + let item_def_id = cx.tcx.hir.local_def_id(it.id); + let t = cx.tcx.type_of(item_def_id); + let param_env = cx.tcx.param_env(item_def_id).reveal_all(); + let ty = cx.tcx.erase_regions(&t); + let layout = ty.layout(cx.tcx, param_env).unwrap_or_else(|e| { + bug!("failed to get layout for `{}`: {}", t, e) }); if let Layout::General { ref variants, ref size, discr, .. } = *layout { diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 8842d30b65c..0ac35a5fdd4 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -547,10 +547,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> Option<u64> { - tcx.infer_ctxt(param_env.reveal_all()).enter(|infcx| { - ty.layout(&infcx).ok().map(|layout| { - layout.size(&tcx.data_layout).bytes() - }) + ty.layout(tcx, param_env).ok().map(|layout| { + layout.size(&tcx.data_layout).bytes() }) } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 56f51cae147..1a13c8e6f3d 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -25,10 +25,10 @@ use type_::Type; use rustc_data_structures::base_n; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::layout::{LayoutTyper, TyLayout}; -use rustc::session::config::{self, NoDebugInfo}; -use rustc::session::Session; -use rustc::util::nodemap::{NodeSet, DefIdMap, FxHashMap}; +use rustc::ty::layout::{LayoutCx, LayoutError, LayoutTyper, TyLayout}; +use session::config::{self, NoDebugInfo}; +use session::Session; +use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; use std::ffi::{CStr, CString}; use std::cell::{Cell, RefCell}; @@ -709,41 +709,27 @@ impl<'a, 'tcx> ty::layout::HasDataLayout for &'a SharedCrateContext<'a, 'tcx> { } } -impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a SharedCrateContext<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { - self.tcx - } -} - impl<'a, 'tcx> ty::layout::HasDataLayout for &'a CrateContext<'a, 'tcx> { fn data_layout(&self) -> &ty::layout::TargetDataLayout { &self.shared.tcx.data_layout } } -impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a CrateContext<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { - self.shared.tcx - } -} - impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> { type TyLayout = TyLayout<'tcx>; - fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { - if let Some(&layout) = self.tcx().layout_cache.borrow().get(&ty) { - return TyLayout { ty: ty, layout: layout, variant_index: None }; - } + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { + self.tcx + } - self.tcx().infer_ctxt(traits::Reveal::All).enter(|infcx| { - infcx.layout_of(ty).unwrap_or_else(|e| { - match e { - ty::layout::LayoutError::SizeOverflow(_) => - self.sess().fatal(&e.to_string()), - _ => bug!("failed to get layout for `{}`: {}", ty, e) - } + fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { + let param_env = ty::ParamEnv::empty(traits::Reveal::All); + LayoutCx::new(self.tcx, param_env) + .layout_of(ty) + .unwrap_or_else(|e| match e { + LayoutError::SizeOverflow(_) => self.sess().fatal(&e.to_string()), + _ => bug!("failed to get layout for `{}`: {}", ty, e) }) - }) } fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> { @@ -754,6 +740,10 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> { impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> { type TyLayout = TyLayout<'tcx>; + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { + self.shared.tcx + } + fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { self.shared.layout_of(ty) } diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index f473d957a90..367f0398fa8 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -46,15 +46,13 @@ pub fn needs_drop_glue<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, t: Ty<'tcx> ty::TyAdt(def, _) if def.is_box() => { let typ = t.boxed_ty(); if !scx.type_needs_drop(typ) && scx.type_is_sized(typ) { - scx.tcx().infer_ctxt(traits::Reveal::All).enter(|infcx| { - let layout = t.layout(&infcx).unwrap(); - if layout.size(scx).bytes() == 0 { - // `Box<ZeroSizeType>` does not allocate. - false - } else { - true - } - }) + let layout = t.layout(scx.tcx(), ty::ParamEnv::empty(traits::Reveal::All)).unwrap(); + if layout.size(scx).bytes() == 0 { + // `Box<ZeroSizeType>` does not allocate. + false + } else { + true + } } else { true } |
