diff --git a/.mailmap b/.mailmap index 679aa55d31458..5673cc5cfbc9d 100644 --- a/.mailmap +++ b/.mailmap @@ -56,6 +56,7 @@ Chris Thorn Chris Thorn Chris Vittal Christopher Vittal Christian Poveda Christian Poveda +Christian Poveda Clark Gaebel Clinton Ryan Corey Richardson Elaine "See More" Nemo @@ -139,6 +140,7 @@ Kang Seonghoon Keegan McAllister Kevin Butler Kyeongwoon Lee +Laurențiu Nicola Lee Jeffery Lee Jeffery Lee Wondong Lennart Kudling diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index ad35204804755..af24cbe1c5c48 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -70,6 +70,7 @@ #![feature(arbitrary_self_types)] #![feature(asm)] #![feature(associated_type_defaults)] +#![feature(bound_cloned)] #![feature(cfg_target_has_atomic)] #![feature(concat_idents)] #![feature(const_fn)] diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index a707f0cc0627a..1b4c4218cc15b 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -696,6 +696,29 @@ pub enum Bound { Unbounded, } +impl Bound<&T> { + /// Map a `Bound<&T>` to a `Bound` by cloning the contents of the bound. + /// + /// # Examples + /// + /// ``` + /// #![feature(bound_cloned)] + /// use std::ops::Bound::*; + /// use std::ops::RangeBounds; + /// + /// assert_eq!((1..12).start_bound(), Included(&1)); + /// assert_eq!((1..12).start_bound().cloned(), Included(1)); + /// ``` + #[unstable(feature = "bound_cloned", issue = "61356")] + pub fn cloned(self) -> Bound { + match self { + Bound::Unbounded => Bound::Unbounded, + Bound::Included(x) => Bound::Included(x.clone()), + Bound::Excluded(x) => Bound::Excluded(x.clone()), + } + } +} + #[stable(feature = "collections_range", since = "1.28.0")] /// `RangeBounds` is implemented by Rust's built-in range types, produced /// by range syntax like `..`, `a..`, `..b`, `..=c`, `d..e`, or `f..=g`. diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 5050842e40971..928bdd7a76002 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -1,3 +1,4 @@ +#![feature(bound_cloned)] #![feature(box_syntax)] #![feature(cell_update)] #![feature(core_private_bignum)] diff --git a/src/libcore/tests/ops.rs b/src/libcore/tests/ops.rs index 78cf07119e729..48755ae4c1641 100644 --- a/src/libcore/tests/ops.rs +++ b/src/libcore/tests/ops.rs @@ -1,4 +1,4 @@ -use core::ops::{Range, RangeFull, RangeFrom, RangeTo, RangeInclusive}; +use core::ops::{Bound, Range, RangeFull, RangeFrom, RangeTo, RangeInclusive}; // Test the Range structs without the syntactic sugar. @@ -82,3 +82,18 @@ fn test_range_is_empty() { assert!( (NAN ..= EPSILON).is_empty()); assert!( (NAN ..= NAN).is_empty()); } + +#[test] +fn test_bound_cloned_unbounded() { + assert_eq!(Bound::<&u32>::Unbounded.cloned(), Bound::Unbounded); +} + +#[test] +fn test_bound_cloned_included() { + assert_eq!(Bound::Included(&3).cloned(), Bound::Included(3)); +} + +#[test] +fn test_bound_cloned_excluded() { + assert_eq!(Bound::Excluded(&3).cloned(), Bound::Excluded(3)); +} diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index dd33fae0d6197..2f19f591830f9 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -151,17 +151,17 @@ macro_rules! make_mir_visitor { self.super_place(place, context, location); } - fn visit_projection(&mut self, - place: & $($mutability)? Projection<'tcx>, + fn visit_place_base(&mut self, + place_base: & $($mutability)? PlaceBase<'tcx>, context: PlaceContext, location: Location) { - self.super_projection(place, context, location); + self.super_place_base(place_base, context, location); } - fn visit_projection_elem(&mut self, - place: & $($mutability)? PlaceElem<'tcx>, - location: Location) { - self.super_projection_elem(place, location); + fn visit_projection(&mut self, + place: & $($mutability)? Projection<'tcx>, + location: Location) { + self.super_projection(place, location); } fn visit_constant(&mut self, @@ -676,36 +676,40 @@ macro_rules! make_mir_visitor { context: PlaceContext, location: Location) { match place { - Place::Base(PlaceBase::Local(local)) => { - self.visit_local(local, context, location); - } - Place::Base(PlaceBase::Static(box Static { kind: _, ty })) => { - self.visit_ty(& $($mutability)? *ty, TyContext::Location(location)); + Place::Base(place_base) => { + self.visit_place_base(place_base, context, location); } Place::Projection(proj) => { - self.visit_projection(proj, context, location); + let context = if context.is_mutating_use() { + PlaceContext::MutatingUse(MutatingUseContext::Projection) + } else { + PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) + }; + + self.visit_place(& $($mutability)? proj.base, context, location); + self.visit_projection(proj, location); } } } - fn super_projection(&mut self, - proj: & $($mutability)? Projection<'tcx>, + fn super_place_base(&mut self, + place_base: & $($mutability)? PlaceBase<'tcx>, context: PlaceContext, location: Location) { - let Projection { base, elem } = proj; - let context = if context.is_mutating_use() { - PlaceContext::MutatingUse(MutatingUseContext::Projection) - } else { - PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) - }; - self.visit_place(base, context, location); - self.visit_projection_elem(elem, location); + match place_base { + PlaceBase::Local(local) => { + self.visit_local(local, context, location); + } + PlaceBase::Static(box Static { kind: _, ty }) => { + self.visit_ty(& $($mutability)? *ty, TyContext::Location(location)); + } + } } - fn super_projection_elem(&mut self, - proj: & $($mutability)? PlaceElem<'tcx>, - location: Location) { - match proj { + fn super_projection(&mut self, + proj: & $($mutability)? Projection<'tcx>, + location: Location) { + match & $($mutability)? proj.elem { ProjectionElem::Deref => { } ProjectionElem::Subslice { from: _, to: _ } => { diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index bb6a13ed15a52..549608bf7ee5f 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -154,51 +154,62 @@ impl<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> context: PlaceContext, location: Location) { debug!("visit_place(place={:?}, context={:?})", place, context); + let mut context = context; let cx = self.fx.cx; - if let mir::Place::Projection(ref proj) = *place { - // Allow uses of projections that are ZSTs or from scalar fields. - let is_consume = match context { - PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => true, - _ => false - }; - if is_consume { - let base_ty = proj.base.ty(self.fx.mir, cx.tcx()); - let base_ty = self.fx.monomorphize(&base_ty); - - // ZSTs don't require any actual memory access. - let elem_ty = base_ty - .projection_ty(cx.tcx(), &proj.elem) - .ty; - let elem_ty = self.fx.monomorphize(&elem_ty); - if cx.layout_of(elem_ty).is_zst() { - return; - } - - if let mir::ProjectionElem::Field(..) = proj.elem { - let layout = cx.layout_of(base_ty.ty); - if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) { - // Recurse with the same context, instead of `Projection`, - // potentially stopping at non-operand projections, - // which would trigger `not_ssa` on locals. - self.visit_place(&proj.base, context, location); + place.iterate(|place_base, place_projections| { + for proj in place_projections { + // Allow uses of projections that are ZSTs or from scalar fields. + let is_consume = match context { + PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => true, + _ => false + }; + if is_consume { + let base_ty = proj.base.ty(self.fx.mir, cx.tcx()); + let base_ty = self.fx.monomorphize(&base_ty); + + // ZSTs don't require any actual memory access. + let elem_ty = base_ty + .projection_ty(cx.tcx(), &proj.elem) + .ty; + let elem_ty = self.fx.monomorphize(&elem_ty); + if cx.layout_of(elem_ty).is_zst() { return; } + + if let mir::ProjectionElem::Field(..) = proj.elem { + let layout = cx.layout_of(base_ty.ty); + if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) { + // Recurse with the same context, instead of `Projection`, + // potentially stopping at non-operand projections, + // which would trigger `not_ssa` on locals. + continue; + } + } } - } - // A deref projection only reads the pointer, never needs the place. - if let mir::ProjectionElem::Deref = proj.elem { - return self.visit_place( - &proj.base, - PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), - location - ); + // A deref projection only reads the pointer, never needs the place. + if let mir::ProjectionElem::Deref = proj.elem { + return self.visit_place( + &proj.base, + PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), + location + ); + } + + context = if context.is_mutating_use() { + PlaceContext::MutatingUse(MutatingUseContext::Projection) + } else { + PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) + }; } - } - self.super_place(place, context, location); + // Default base visit behavior + if let mir::PlaceBase::Local(local) = place_base { + self.visit_local(local, context, location); + } + }); } fn visit_local(&mut self, diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index eed051449e155..91b4af9655a43 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -185,7 +185,7 @@ use rustc::ty::{self, TypeFoldable, Ty, TyCtxt, GenericParamDefKind, Instance}; use rustc::ty::print::obsolete::DefPathBasedNames; use rustc::ty::adjustment::{CustomCoerceUnsized, PointerCast}; use rustc::session::config::EntryFnType; -use rustc::mir::{self, Location, Place, PlaceBase, Promoted, Static, StaticKind}; +use rustc::mir::{self, Location, PlaceBase, Promoted, Static, StaticKind}; use rustc::mir::visit::Visitor as MirVisitor; use rustc::mir::mono::{MonoItem, InstantiationMode}; use rustc::mir::interpret::{Scalar, GlobalId, GlobalAlloc, ErrorHandled}; @@ -655,14 +655,12 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.super_terminator_kind(kind, location); } - fn visit_place(&mut self, - place: &mir::Place<'tcx>, - context: mir::visit::PlaceContext, - location: Location) { - match place { - Place::Base( - PlaceBase::Static(box Static{ kind:StaticKind::Static(def_id), .. }) - ) => { + fn visit_place_base(&mut self, + place_base: &mir::PlaceBase<'tcx>, + _context: mir::visit::PlaceContext, + location: Location) { + match place_base { + PlaceBase::Static(box Static { kind: StaticKind::Static(def_id), .. }) => { debug!("visiting static {:?} @ {:?}", def_id, location); let tcx = self.tcx; @@ -671,10 +669,13 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.output.push(MonoItem::Static(*def_id)); } } - _ => {} + PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. }) => { + // FIXME: should we handle promoteds here instead of eagerly in collect_neighbours? + } + PlaceBase::Local(_) => { + // Locals have no relevance for collector + } } - - self.super_place(place, context, location); } } diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 8ec8a8fa12eec..4e8cc124e5040 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -199,11 +199,39 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, - location: Location) { - match place { - &Place::Projection(box Projection { - ref base, ref elem - }) => { + _location: Location) { + place.iterate(|place_base, place_projections| { + match place_base { + PlaceBase::Local(..) => { + // Locals are safe. + } + PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. }) => { + bug!("unsafety checking should happen before promotion") + } + PlaceBase::Static(box Static { kind: StaticKind::Static(def_id), .. }) => { + if self.tcx.is_mutable_static(*def_id) { + self.require_unsafe("use of mutable static", + "mutable statics can be mutated by multiple threads: aliasing \ + violations or data races will cause undefined behavior", + UnsafetyViolationKind::General); + } else if self.tcx.is_foreign_item(*def_id) { + let source_info = self.source_info; + let lint_root = + self.source_scope_local_data[source_info.scope].lint_root; + self.register_violations(&[UnsafetyViolation { + source_info, + description: InternedString::intern("use of extern static"), + details: InternedString::intern( + "extern statics are not controlled by the Rust type system: \ + invalid data, aliasing violations or data races will cause \ + undefined behavior"), + kind: UnsafetyViolationKind::ExternStatic(lint_root) + }], &[]); + } + } + } + + for proj in place_projections { if context.is_borrow() { if util::is_disaligned(self.tcx, self.mir, self.param_env, place) { let source_info = self.source_info; @@ -220,7 +248,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { }], &[]); } } - let is_borrow_of_interior_mut = context.is_borrow() && !base + let is_borrow_of_interior_mut = context.is_borrow() && !proj.base .ty(self.mir, self.tcx) .ty .is_freeze(self.tcx, self.param_env, self.source_info.span); @@ -236,7 +264,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { ); } let old_source_info = self.source_info; - if let &Place::Base(PlaceBase::Local(local)) = base { + if let Place::Base(PlaceBase::Local(local)) = proj.base { if self.mir.local_decls[local].internal { // Internal locals are used in the `move_val_init` desugaring. // We want to check unsafety against the source info of the @@ -244,7 +272,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { self.source_info = self.mir.local_decls[local].source_info; } } - let base_ty = base.ty(self.mir, self.tcx).ty; + let base_ty = proj.base.ty(self.mir, self.tcx).ty; match base_ty.sty { ty::RawPtr(..) => { self.require_unsafe("dereference of raw pointer", @@ -260,8 +288,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { MutatingUseContext::AsmOutput ) { - let elem_ty = match elem { - &ProjectionElem::Field(_, ty) => ty, + let elem_ty = match proj.elem { + ProjectionElem::Field(_, ty) => ty, _ => span_bug!( self.source_info.span, "non-field projection {:?} from union?", @@ -292,36 +320,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } self.source_info = old_source_info; } - &Place::Base(PlaceBase::Local(..)) => { - // locals are safe - } - &Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. })) => { - bug!("unsafety checking should happen before promotion") - } - &Place::Base( - PlaceBase::Static(box Static { kind: StaticKind::Static(def_id), .. }) - ) => { - if self.tcx.is_mutable_static(def_id) { - self.require_unsafe("use of mutable static", - "mutable statics can be mutated by multiple threads: aliasing violations \ - or data races will cause undefined behavior", - UnsafetyViolationKind::General); - } else if self.tcx.is_foreign_item(def_id) { - let source_info = self.source_info; - let lint_root = - self.source_scope_local_data[source_info.scope].lint_root; - self.register_violations(&[UnsafetyViolation { - source_info, - description: InternedString::intern("use of extern static"), - details: InternedString::intern( - "extern statics are not controlled by the Rust type system: invalid \ - data, aliasing violations or data races will cause undefined behavior"), - kind: UnsafetyViolationKind::ExternStatic(lint_root) - }], &[]); - } - } - }; - self.super_place(place, context, location); + }); } }