From f8b66a001d74946565ee2e7df58afc9918455da1 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Fri, 19 May 2017 13:43:06 -0500 Subject: [PATCH 01/13] trace_macro: Show both the macro call and its expansion. #42072. --- src/libsyntax/ext/tt/macro_rules.rs | 15 ++++++++++++--- src/test/ui/macros/trace-macro.stderr | 7 +++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index a208f530602a5..d3da32304aa04 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -84,6 +84,12 @@ impl TTMacroExpander for MacroRulesMacroExpander { } } +fn trace_macros_note(cx: &mut ExtCtxt, sp: Span, message: String) { + let sp = sp.macro_backtrace().last().map(|trace| trace.call_site).unwrap_or(sp); + let mut values: &mut Vec = cx.expansions.entry(sp).or_insert_with(Vec::new); + values.push(message); +} + /// Given `lhses` and `rhses`, this is the new macro we create fn generic_extension<'cx>(cx: &'cx mut ExtCtxt, sp: Span, @@ -93,9 +99,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt, rhses: &[quoted::TokenTree]) -> Box { if cx.trace_macros() { - let sp = sp.macro_backtrace().last().map(|trace| trace.call_site).unwrap_or(sp); - let mut values: &mut Vec = cx.expansions.entry(sp).or_insert_with(Vec::new); - values.push(format!("expands to `{}! {{ {} }}`", name, arg)); + trace_macros_note(cx, sp, format!("expanding `{}! {{ {} }}`", name, arg)); } // Which arm's failure should we report? (the one furthest along) @@ -117,6 +121,11 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt, }; // rhs has holes ( `$id` and `$(...)` that need filled) let tts = transcribe(&cx.parse_sess.span_diagnostic, Some(named_matches), rhs); + + if cx.trace_macros() { + trace_macros_note(cx, sp, format!("to `{}`", tts)); + } + let directory = Directory { path: cx.current_expansion.module.directory.clone(), ownership: cx.current_expansion.directory_ownership, diff --git a/src/test/ui/macros/trace-macro.stderr b/src/test/ui/macros/trace-macro.stderr index 09117a4ca7404..6cf3b0bd35d5e 100644 --- a/src/test/ui/macros/trace-macro.stderr +++ b/src/test/ui/macros/trace-macro.stderr @@ -4,6 +4,9 @@ note: trace_macro 14 | println!("Hello, World!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expands to `println! { "Hello, World!" }` - = note: expands to `print! { concat ! ( "Hello, World!" , "/n" ) }` + = note: expanding `println! { "Hello, World!" }` + = note: to `print ! ( concat ! ( "Hello, World!" , "/n" ) )` + = note: expanding `print! { concat ! ( "Hello, World!" , "/n" ) }` + = note: to `$crate :: io :: _print ( format_args ! ( concat ! ( "Hello, World!" , "/n" ) ) + )` From dec23d41a607b78c590ab9672815ff53c1e282a7 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Sun, 21 May 2017 16:00:04 +0200 Subject: [PATCH 02/13] Update Rc and Arc documentation. It was decided in the RFC discussion https://github.com/rust-lang/rfcs/pull/1954 to make the function call syntax Rc::clone(&foo) the idiomatic way to clone a reference counted pointer (over the method call syntax foo.clone(). This change updates the documentation of Rc, Arc and their respoective Weak pointers to reflect it and bring more exposure to the existence of the function call syntax. --- src/liballoc/arc.rs | 44 +++++++++++++++++++++++++++++------------ src/liballoc/rc.rs | 48 +++++++++++++++++++++++++++++++-------------- 2 files changed, 64 insertions(+), 28 deletions(-) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 27ecefe043b1e..5faf4dcccaf91 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -91,6 +91,24 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize; /// strong `Arc` pointers from parent nodes to children, and [`Weak`][weak] /// pointers from children back to their parents. /// +/// # Cloning references +/// +/// Creating a new reference from an existing reference counted pointer is done using the +/// `Clone` trait implemented for [`Arc`][`arc`] and [`Weak`][`weak`]. +/// +/// ``` +/// use std::sync::Arc; +/// let foo = Arc::new(vec![1.0, 2.0, 3.0]); +/// // The two syntaxes below are equivalent. +/// let a = foo.clone(); +/// let b = Arc::clone(&foo); +/// // a and b both point to the same memory location as foo. +/// ``` +/// +/// The `Arc::clone(&from)` syntax is the most idiomatic because it conveys more explicitly +/// the meaning of the code. In the example above, this syntax makes it easier to see that +/// this code is creating a new reference rather than copying the whole content of foo. +/// /// ## `Deref` behavior /// /// `Arc` automatically dereferences to `T` (via the [`Deref`][deref] trait), @@ -138,7 +156,7 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize; /// let five = Arc::new(5); /// /// for _ in 0..10 { -/// let five = five.clone(); +/// let five = Arc::clone(&five); /// /// thread::spawn(move || { /// println!("{:?}", five); @@ -158,7 +176,7 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize; /// let val = Arc::new(AtomicUsize::new(5)); /// /// for _ in 0..10 { -/// let val = val.clone(); +/// let val = Arc::clone(&val); /// /// thread::spawn(move || { /// let v = val.fetch_add(1, Ordering::SeqCst); @@ -282,7 +300,7 @@ impl Arc { /// assert_eq!(Arc::try_unwrap(x), Ok(3)); /// /// let x = Arc::new(4); - /// let _y = x.clone(); + /// let _y = Arc::clone(&x); /// assert_eq!(*Arc::try_unwrap(x).unwrap_err(), 4); /// ``` #[inline] @@ -451,7 +469,7 @@ impl Arc { /// use std::sync::Arc; /// /// let five = Arc::new(5); - /// let _also_five = five.clone(); + /// let _also_five = Arc::clone(&five); /// /// // This assertion is deterministic because we haven't shared /// // the `Arc` between threads. @@ -499,7 +517,7 @@ impl Arc { /// use std::sync::Arc; /// /// let five = Arc::new(5); - /// let same_five = five.clone(); + /// let same_five = Arc::clone(&five); /// let other_five = Arc::new(5); /// /// assert!(Arc::ptr_eq(&five, &same_five)); @@ -524,7 +542,7 @@ impl Clone for Arc { /// /// let five = Arc::new(5); /// - /// five.clone(); + /// Arc::clone(&five); /// ``` #[inline] fn clone(&self) -> Arc { @@ -591,7 +609,7 @@ impl Arc { /// let mut data = Arc::new(5); /// /// *Arc::make_mut(&mut data) += 1; // Won't clone anything - /// let mut other_data = data.clone(); // Won't clone inner data + /// let mut other_data = Arc::clone(&data); // Won't clone inner data /// *Arc::make_mut(&mut data) += 1; // Clones inner data /// *Arc::make_mut(&mut data) += 1; // Won't clone anything /// *Arc::make_mut(&mut other_data) *= 2; // Won't clone anything @@ -679,7 +697,7 @@ impl Arc { /// *Arc::get_mut(&mut x).unwrap() = 4; /// assert_eq!(*x, 4); /// - /// let _y = x.clone(); + /// let _y = Arc::clone(&x); /// assert!(Arc::get_mut(&mut x).is_none()); /// ``` #[inline] @@ -751,7 +769,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Arc { /// } /// /// let foo = Arc::new(Foo); - /// let foo2 = foo.clone(); + /// let foo2 = Arc::clone(&foo); /// /// drop(foo); // Doesn't print anything /// drop(foo2); // Prints "dropped!" @@ -903,11 +921,11 @@ impl Clone for Weak { /// # Examples /// /// ``` - /// use std::sync::Arc; + /// use std::sync::{Arc, Weak}; /// /// let weak_five = Arc::downgrade(&Arc::new(5)); /// - /// weak_five.clone(); + /// Weak::clone(&weak_five); /// ``` #[inline] fn clone(&self) -> Weak { @@ -956,7 +974,7 @@ impl Drop for Weak { /// # Examples /// /// ``` - /// use std::sync::Arc; + /// use std::sync::{Arc, Weak}; /// /// struct Foo; /// @@ -968,7 +986,7 @@ impl Drop for Weak { /// /// let foo = Arc::new(Foo); /// let weak_foo = Arc::downgrade(&foo); - /// let other_weak_foo = weak_foo.clone(); + /// let other_weak_foo = Weak::clone(&weak_foo); /// /// drop(weak_foo); // Doesn't print anything /// drop(foo); // Prints "dropped!" diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index d6dbf77bfac77..33951b911dd51 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -55,6 +55,24 @@ //! [`Weak`][`Weak`] does not auto-dereference to `T`, because the value may have //! already been destroyed. //! +//! # Cloning references +//! +//! Creating a new reference from an existing reference counted pointer is done using the +//! `Clone` trait implemented for [`Rc`][`Rc`] and [`Weak`][`Weak`]. +//! +//! ``` +//! use std::rc::Rc; +//! let foo = Rc::new(vec![1.0, 2.0, 3.0]); +//! // The two syntaxes below are equivalent. +//! let a = foo.clone(); +//! let b = Rc::clone(&foo); +//! // a and b both point to the same memory location as foo. +//! ``` +//! +//! The `Rc::clone(&from)` syntax is the most idiomatic because it conveys more explicitly +//! the meaning of the code. In the example above, this syntax makes it easier to see that +//! this code is creating a new reference rather than copying the whole content of foo. +//! //! # Examples //! //! Consider a scenario where a set of `Gadget`s are owned by a given `Owner`. @@ -90,11 +108,11 @@ //! // the reference count in the process. //! let gadget1 = Gadget { //! id: 1, -//! owner: gadget_owner.clone(), +//! owner: Rc::clone(&gadget_owner), //! }; //! let gadget2 = Gadget { //! id: 2, -//! owner: gadget_owner.clone(), +//! owner: Rc::clone(&gadget_owner), //! }; //! //! // Dispose of our local variable `gadget_owner`. @@ -163,13 +181,13 @@ //! let gadget1 = Rc::new( //! Gadget { //! id: 1, -//! owner: gadget_owner.clone(), +//! owner: Rc::clone(&gadget_owner), //! } //! ); //! let gadget2 = Rc::new( //! Gadget { //! id: 2, -//! owner: gadget_owner.clone(), +//! owner: Rc::clone(&gadget_owner), //! } //! ); //! @@ -316,7 +334,7 @@ impl Rc { /// assert_eq!(Rc::try_unwrap(x), Ok(3)); /// /// let x = Rc::new(4); - /// let _y = x.clone(); + /// let _y = Rc::clone(&x); /// assert_eq!(*Rc::try_unwrap(x).unwrap_err(), 4); /// ``` #[inline] @@ -508,7 +526,7 @@ impl Rc { /// use std::rc::Rc; /// /// let five = Rc::new(5); - /// let _also_five = five.clone(); + /// let _also_five = Rc::clone(&five); /// /// assert_eq!(2, Rc::strong_count(&five)); /// ``` @@ -550,7 +568,7 @@ impl Rc { /// *Rc::get_mut(&mut x).unwrap() = 4; /// assert_eq!(*x, 4); /// - /// let _y = x.clone(); + /// let _y = Rc::clone(&x); /// assert!(Rc::get_mut(&mut x).is_none()); /// ``` #[inline] @@ -576,7 +594,7 @@ impl Rc { /// use std::rc::Rc; /// /// let five = Rc::new(5); - /// let same_five = five.clone(); + /// let same_five = Rc::clone(&five); /// let other_five = Rc::new(5); /// /// assert!(Rc::ptr_eq(&five, &same_five)); @@ -608,7 +626,7 @@ impl Rc { /// let mut data = Rc::new(5); /// /// *Rc::make_mut(&mut data) += 1; // Won't clone anything - /// let mut other_data = data.clone(); // Won't clone inner data + /// let mut other_data = Rc::clone(&data); // Won't clone inner data /// *Rc::make_mut(&mut data) += 1; // Clones inner data /// *Rc::make_mut(&mut data) += 1; // Won't clone anything /// *Rc::make_mut(&mut other_data) *= 2; // Won't clone anything @@ -680,7 +698,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { /// } /// /// let foo = Rc::new(Foo); - /// let foo2 = foo.clone(); + /// let foo2 = Rc::clone(&foo); /// /// drop(foo); // Doesn't print anything /// drop(foo2); // Prints "dropped!" @@ -720,7 +738,7 @@ impl Clone for Rc { /// /// let five = Rc::new(5); /// - /// five.clone(); + /// Rc::clone(&five); /// ``` #[inline] fn clone(&self) -> Rc { @@ -1050,7 +1068,7 @@ impl Drop for Weak { /// # Examples /// /// ``` - /// use std::rc::Rc; + /// use std::rc::{Rc, Weak}; /// /// struct Foo; /// @@ -1062,7 +1080,7 @@ impl Drop for Weak { /// /// let foo = Rc::new(Foo); /// let weak_foo = Rc::downgrade(&foo); - /// let other_weak_foo = weak_foo.clone(); + /// let other_weak_foo = Weak::clone(&weak_foo); /// /// drop(weak_foo); // Doesn't print anything /// drop(foo); // Prints "dropped!" @@ -1090,11 +1108,11 @@ impl Clone for Weak { /// # Examples /// /// ``` - /// use std::rc::Rc; + /// use std::rc::{Rc, Weak}; /// /// let weak_five = Rc::downgrade(&Rc::new(5)); /// - /// weak_five.clone(); + /// Weak::clone(&weak_five); /// ``` #[inline] fn clone(&self) -> Weak { From 57f260d41895ec6aa4f00412287c6fdfe63aa23f Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 23 May 2017 02:24:25 -0700 Subject: [PATCH 03/13] Override size_hint and propagate ExactSizeIterator for iter::StepBy Generally useful, but also a prerequisite for moving a bunch of unit tests off Range::step_by. --- src/libcore/iter/mod.rs | 19 ++++++++++ src/libcore/tests/iter.rs | 73 +++++++++++++++++++++++++++++++++++++++ src/libcore/tests/lib.rs | 2 ++ 3 files changed, 94 insertions(+) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 420ff0f71193b..a3b755a38f3d0 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -553,8 +553,27 @@ impl Iterator for StepBy where I: Iterator { self.iter.nth(self.step) } } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let inner_hint = self.iter.size_hint(); + + if self.first_take { + let f = |n| if n == 0 { 0 } else { 1 + (n-1)/(self.step+1) }; + (f(inner_hint.0), inner_hint.1.map(f)) + } else { + let f = |n| n / (self.step+1); + (f(inner_hint.0), inner_hint.1.map(f)) + } + } } +// StepBy can only make the iterator shorter, so the len will still fit. +#[unstable(feature = "iterator_step_by", + reason = "unstable replacement of Range::step_by", + issue = "27741")] +impl ExactSizeIterator for StepBy where I: ExactSizeIterator {} + /// An iterator that strings two iterators together. /// /// This `struct` is created by the [`chain`] method on [`Iterator`]. See its diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index ad91ba9be58f2..4030eaf2b2333 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -171,6 +171,79 @@ fn test_iterator_step_by_zero() { it.next(); } +#[test] +fn test_iterator_step_by_size_hint() { + struct StubSizeHint(usize, Option); + impl Iterator for StubSizeHint { + type Item = (); + fn next(&mut self) -> Option<()> { + self.0 -= 1; + if let Some(ref mut upper) = self.1 { + *upper -= 1; + } + Some(()) + } + fn size_hint(&self) -> (usize, Option) { + (self.0, self.1) + } + } + + // The two checks in each case are needed because the logic + // is different before the first call to `next()`. + + let mut it = StubSizeHint(10, Some(10)).step_by(1); + assert_eq!(it.size_hint(), (10, Some(10))); + it.next(); + assert_eq!(it.size_hint(), (9, Some(9))); + + // exact multiple + let mut it = StubSizeHint(10, Some(10)).step_by(3); + assert_eq!(it.size_hint(), (4, Some(4))); + it.next(); + assert_eq!(it.size_hint(), (3, Some(3))); + + // larger base range, but not enough to get another element + let mut it = StubSizeHint(12, Some(12)).step_by(3); + assert_eq!(it.size_hint(), (4, Some(4))); + it.next(); + assert_eq!(it.size_hint(), (3, Some(3))); + + // smaller base range, so fewer resulting elements + let mut it = StubSizeHint(9, Some(9)).step_by(3); + assert_eq!(it.size_hint(), (3, Some(3))); + it.next(); + assert_eq!(it.size_hint(), (2, Some(2))); + + // infinite upper bound + let mut it = StubSizeHint(usize::MAX, None).step_by(1); + assert_eq!(it.size_hint(), (usize::MAX, None)); + it.next(); + assert_eq!(it.size_hint(), (usize::MAX-1, None)); + + // still infinite with larger step + let mut it = StubSizeHint(7, None).step_by(3); + assert_eq!(it.size_hint(), (3, None)); + it.next(); + assert_eq!(it.size_hint(), (2, None)); + + // propagates ExactSizeIterator + let a = [1,2,3,4,5]; + let it = a.iter().step_by(2); + assert_eq!(it.len(), 3); + + // Cannot be TrustedLen as a step greater than one makes an iterator + // with (usize::MAX, None) no longer meet the safety requirements + trait TrustedLenCheck { fn test(self) -> bool; } + impl TrustedLenCheck for T { + default fn test(self) -> bool { false } + } + impl TrustedLenCheck for T { + fn test(self) -> bool { true } + } + assert!(TrustedLenCheck::test(a.iter())); + assert!(!TrustedLenCheck::test(a.iter().step_by(1))); +} + #[test] fn test_filter_map() { let it = (0..).step_by(1).take(10) diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index c52155ead4f0b..d5d7d0f40b210 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -31,9 +31,11 @@ #![feature(slice_patterns)] #![feature(sort_internals)] #![feature(sort_unstable)] +#![feature(specialization)] #![feature(step_by)] #![feature(step_trait)] #![feature(test)] +#![feature(trusted_len)] #![feature(try_from)] #![feature(unicode)] #![feature(unique)] From 4be488c06581448abb9ad8cfc98fa32bcf72244d Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 20 May 2017 18:05:18 -0700 Subject: [PATCH 04/13] Add iterator_step_by to the unstable book's summary --- src/doc/unstable-book/src/SUMMARY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 39f800591483b..50efcd06220b3 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -156,6 +156,7 @@ - [io](library-features/io.md) - [ip](library-features/ip.md) - [iter_rfind](library-features/iter-rfind.md) + - [iterator_step_by](library-features/iterator-step-by.md) - [libstd_io_internals](library-features/libstd-io-internals.md) - [libstd_sys_internals](library-features/libstd-sys-internals.md) - [libstd_thread_internals](library-features/libstd-thread-internals.md) From fcb3a7109c84f48c4f60504255dd3f375818fdfd Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 20 May 2017 18:32:43 -0700 Subject: [PATCH 05/13] Update description of iter::StepBy --- src/libcore/iter/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index a3b755a38f3d0..f87bbfbd7d9ae 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -520,7 +520,7 @@ impl Iterator for Cycle where I: Clone + Iterator { #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for Cycle where I: Clone + Iterator {} -/// An iterator that steps by n elements every iteration. +/// An adapter for stepping iterators by a custom amount. /// /// This `struct` is created by the [`step_by`] method on [`Iterator`]. See /// its documentation for more. From 21dd71f51460eb791dc5f938ad4b02b76c6c8520 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 23 May 2017 16:21:24 +0200 Subject: [PATCH 06/13] incr.comp.: Track expanded spans instead of FileMaps. --- src/librustc/dep_graph/dep_node.rs | 2 - src/librustc/ich/caching_codemap_view.rs | 28 +---------- src/librustc/ich/hcx.rs | 5 ++ src/librustc/ich/impls_mir.rs | 50 +++++++++++++++++-- src/librustc/session/mod.rs | 23 ++------- src/librustc_incremental/calculate_svh/mod.rs | 26 +--------- src/librustc_incremental/persist/hash.rs | 18 +------ src/librustc_metadata/encoder.rs | 22 ++------ src/librustc_metadata/isolated_encoder.rs | 12 ++++- src/libsyntax/codemap.rs | 28 ----------- .../rlib_cross_crate/auxiliary/a.rs | 1 + .../type_alias_cross_crate/auxiliary/a.rs | 2 + 12 files changed, 78 insertions(+), 139 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 291d0d7c937ed..38ad473e4042f 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -176,7 +176,6 @@ pub enum DepNode { IsMirAvailable(D), ItemAttrs(D), FnArgNames(D), - FileMap(D, Arc), } impl DepNode { @@ -307,7 +306,6 @@ impl DepNode { ConstIsRvaluePromotableToStatic(ref d) => op(d).map(ConstIsRvaluePromotableToStatic), IsMirAvailable(ref d) => op(d).map(IsMirAvailable), GlobalMetaData(ref d, kind) => op(d).map(|d| GlobalMetaData(d, kind)), - FileMap(ref d, ref file_name) => op(d).map(|d| FileMap(d, file_name.clone())), } } } diff --git a/src/librustc/ich/caching_codemap_view.rs b/src/librustc/ich/caching_codemap_view.rs index b21c3a2b21600..9aecd8ad83602 100644 --- a/src/librustc/ich/caching_codemap_view.rs +++ b/src/librustc/ich/caching_codemap_view.rs @@ -8,11 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use dep_graph::{DepGraph, DepNode}; -use hir::def_id::{DefId, CrateNum, CRATE_DEF_INDEX}; -use rustc_data_structures::bitvec::BitVector; use std::rc::Rc; -use std::sync::Arc; use syntax::codemap::CodeMap; use syntax_pos::{BytePos, FileMap}; use ty::TyCtxt; @@ -31,14 +27,12 @@ pub struct CachingCodemapView<'tcx> { codemap: &'tcx CodeMap, line_cache: [CacheEntry; 3], time_stamp: usize, - dep_graph: DepGraph, - dep_tracking_reads: BitVector, } impl<'tcx> CachingCodemapView<'tcx> { pub fn new<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CachingCodemapView<'tcx> { let codemap = tcx.sess.codemap(); - let files = codemap.files_untracked(); + let files = codemap.files(); let first_file = files[0].clone(); let entry = CacheEntry { time_stamp: 0, @@ -50,11 +44,9 @@ impl<'tcx> CachingCodemapView<'tcx> { }; CachingCodemapView { - dep_graph: tcx.dep_graph.clone(), codemap: codemap, line_cache: [entry.clone(), entry.clone(), entry.clone()], time_stamp: 0, - dep_tracking_reads: BitVector::new(files.len()), } } @@ -67,9 +59,6 @@ impl<'tcx> CachingCodemapView<'tcx> { for cache_entry in self.line_cache.iter_mut() { if pos >= cache_entry.line_start && pos < cache_entry.line_end { cache_entry.time_stamp = self.time_stamp; - if self.dep_tracking_reads.insert(cache_entry.file_index) { - self.dep_graph.read(dep_node(cache_entry)); - } return Some((cache_entry.file.clone(), cache_entry.line_number, @@ -90,7 +79,7 @@ impl<'tcx> CachingCodemapView<'tcx> { // If the entry doesn't point to the correct file, fix it up if pos < cache_entry.file.start_pos || pos >= cache_entry.file.end_pos { let file_valid; - let files = self.codemap.files_untracked(); + let files = self.codemap.files(); if files.len() > 0 { let file_index = self.codemap.lookup_filemap_idx(pos); @@ -120,21 +109,8 @@ impl<'tcx> CachingCodemapView<'tcx> { cache_entry.line_end = line_bounds.1; cache_entry.time_stamp = self.time_stamp; - if self.dep_tracking_reads.insert(cache_entry.file_index) { - self.dep_graph.read(dep_node(cache_entry)); - } - return Some((cache_entry.file.clone(), cache_entry.line_number, pos - cache_entry.line_start)); } } - -fn dep_node(cache_entry: &CacheEntry) -> DepNode { - let def_id = DefId { - krate: CrateNum::from_u32(cache_entry.file.crate_of_origin), - index: CRATE_DEF_INDEX, - }; - let name = Arc::new(cache_entry.file.name.clone()); - DepNode::FileMap(def_id, name) -} diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index f25ec8ecd4d71..f8dddc42e48cc 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -74,6 +74,11 @@ impl<'a, 'tcx: 'a> StableHashingContext<'a, 'tcx> { } } + pub fn force_span_hashing(mut self) -> Self { + self.hash_spans = true; + self + } + #[inline] pub fn while_hashing_hir_bodies(&mut self, hash_bodies: bool, diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 3ff8ffb35054a..d523d40ccd4ab 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -22,11 +22,55 @@ impl_stable_hash_for!(struct mir::SourceInfo { span, scope }); impl_stable_hash_for!(enum mir::Mutability { Mut, Not }); impl_stable_hash_for!(enum mir::BorrowKind { Shared, Unique, Mut }); impl_stable_hash_for!(enum mir::LocalKind { Var, Temp, Arg, ReturnPointer }); -impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { mutability, ty, name, source_info, -is_user_variable}); +impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { + mutability, + ty, + name, + source_info, + is_user_variable +}); impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, by_ref }); impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, is_cleanup }); -impl_stable_hash_for!(struct mir::Terminator<'tcx> { source_info, kind }); + +impl<'a, 'tcx> HashStable> for mir::Terminator<'tcx> { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let mir::Terminator { + ref kind, + ref source_info, + } = *self; + + let hash_spans_unconditionally = match *kind { + mir::TerminatorKind::Assert { .. } => { + // Assert terminators generate a panic message that contains the + // source location, so we always have to feed its span into the + // ICH. + true + } + mir::TerminatorKind::Goto { .. } | + mir::TerminatorKind::SwitchInt { .. } | + mir::TerminatorKind::Resume | + mir::TerminatorKind::Return | + mir::TerminatorKind::Unreachable | + mir::TerminatorKind::Drop { .. } | + mir::TerminatorKind::DropAndReplace { .. } | + mir::TerminatorKind::Call { .. } => false, + }; + + if hash_spans_unconditionally { + hcx.while_hashing_spans(true, |hcx| { + source_info.hash_stable(hcx, hasher); + }) + } else { + source_info.hash_stable(hcx, hasher); + } + + kind.hash_stable(hcx, hasher); + } +} + impl<'a, 'tcx> HashStable> for mir::Local { #[inline] diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 814246330a4c2..28531893659e6 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -11,8 +11,9 @@ pub use self::code_stats::{CodeStats, DataTypeKind, FieldInfo}; pub use self::code_stats::{SizeKind, TypeSizeInfo, VariantInfo}; -use dep_graph::{DepGraph, DepNode}; -use hir::def_id::{DefId, CrateNum, DefIndex, CRATE_DEF_INDEX}; +use dep_graph::DepGraph; +use hir::def_id::{CrateNum, DefIndex}; + use lint; use middle::cstore::CrateStore; use middle::dependency_format; @@ -32,7 +33,7 @@ use syntax::parse::ParseSess; use syntax::symbol::Symbol; use syntax::{ast, codemap}; use syntax::feature_gate::AttributeType; -use syntax_pos::{Span, MultiSpan, FileMap}; +use syntax_pos::{Span, MultiSpan}; use rustc_back::{LinkerFlavor, PanicStrategy}; use rustc_back::target::Target; @@ -46,7 +47,6 @@ use std::io::Write; use std::rc::Rc; use std::fmt; use std::time::Duration; -use std::sync::Arc; mod code_stats; pub mod config; @@ -626,21 +626,6 @@ pub fn build_session_(sopts: config::Options, }; let target_cfg = config::build_target_config(&sopts, &span_diagnostic); - // Hook up the codemap with a callback that allows it to register FileMap - // accesses with the dependency graph. - let cm_depgraph = dep_graph.clone(); - let codemap_dep_tracking_callback = Box::new(move |filemap: &FileMap| { - let def_id = DefId { - krate: CrateNum::from_u32(filemap.crate_of_origin), - index: CRATE_DEF_INDEX, - }; - let name = Arc::new(filemap.name.clone()); - let dep_node = DepNode::FileMap(def_id, name); - - cm_depgraph.read(dep_node); - }); - codemap.set_dep_tracking_callback(codemap_dep_tracking_callback); - let p_s = parse::ParseSess::with_span_handler(span_diagnostic, codemap); let default_sysroot = match sopts.maybe_sysroot { Some(_) => None, diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index c9ed9ad3c7d2d..f5727aa0a5ecc 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -29,10 +29,9 @@ use std::cell::RefCell; use std::hash::Hash; -use std::sync::Arc; use rustc::dep_graph::DepNode; use rustc::hir; -use rustc::hir::def_id::{LOCAL_CRATE, CRATE_DEF_INDEX, DefId}; +use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::ich::{Fingerprint, StableHashingContext}; use rustc::ty::TyCtxt; @@ -155,11 +154,6 @@ impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> { // We want to incoporate these into the // SVH. } - DepNode::FileMap(..) => { - // These don't make a semantic - // difference, filter them out. - return None - } DepNode::AllLocalTraitImpls => { // These are already covered by hashing // the HIR. @@ -306,24 +300,6 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) visitor.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, macro_def); } - for filemap in tcx.sess - .codemap() - .files_untracked() - .iter() - .filter(|fm| !fm.is_imported()) { - assert_eq!(LOCAL_CRATE.as_u32(), filemap.crate_of_origin); - let def_id = DefId { - krate: LOCAL_CRATE, - index: CRATE_DEF_INDEX, - }; - let name = Arc::new(filemap.name.clone()); - let dep_node = DepNode::FileMap(def_id, name); - let mut hasher = IchHasher::new(); - filemap.hash_stable(&mut visitor.hcx, &mut hasher); - let fingerprint = hasher.finish(); - visitor.hashes.insert(dep_node, fingerprint); - } - visitor.compute_and_store_ich_for_trait_impls(krate); }); diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs index 2f727a80f016e..6ab280be470dd 100644 --- a/src/librustc_incremental/persist/hash.rs +++ b/src/librustc_incremental/persist/hash.rs @@ -51,8 +51,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { match *dep_node { DepNode::Krate | DepNode::Hir(_) | - DepNode::HirBody(_) | - DepNode::FileMap(..) => + DepNode::HirBody(_) => true, DepNode::MetaData(def_id) | DepNode::GlobalMetaData(def_id, _) => !def_id.is_local(), @@ -77,20 +76,6 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { Some(self.incremental_hashes_map[dep_node]) } - DepNode::FileMap(def_id, ref name) => { - if def_id.is_local() { - // We will have been able to retrace the DefId (which is - // always the local CRATE_DEF_INDEX), but the file with the - // given name might have been removed, so we use get() in - // order to allow for that case. - self.incremental_hashes_map.get(dep_node).map(|x| *x) - } else { - Some(self.metadata_hash(DepNode::FileMap(def_id, name.clone()), - def_id.krate, - |this| &mut this.global_metadata_hashes)) - } - } - // MetaData from other crates is an *input* to us. // MetaData nodes from *our* crates are an *output*; we // don't hash them, but we do compute a hash for them and @@ -242,7 +227,6 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX }; let dep_node = match dep_node { DepNode::GlobalMetaData(_, kind) => DepNode::GlobalMetaData(def_id, kind), - DepNode::FileMap(_, name) => DepNode::FileMap(def_id, name), other => { bug!("unexpected DepNode variant: {:?}", other) } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 93fcdc455e5dd..317b14e4ad27d 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -18,7 +18,7 @@ use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary, use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId, LOCAL_CRATE}; use rustc::hir::map::definitions::DefPathTable; use rustc::dep_graph::{DepNode, GlobalMetaDataKind}; -use rustc::ich::{StableHashingContext, Fingerprint}; +use rustc::ich::Fingerprint; use rustc::middle::dependency_format::Linkage; use rustc::middle::lang_items; use rustc::mir; @@ -29,7 +29,6 @@ use rustc::session::config::{self, CrateTypeProcMacro}; use rustc::util::nodemap::{FxHashMap, NodeSet}; use rustc_serialize::{Encodable, Encoder, SpecializedEncoder, opaque}; -use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; use std::hash::Hash; use std::intrinsics; @@ -37,7 +36,6 @@ use std::io::prelude::*; use std::io::Cursor; use std::path::Path; use std::rc::Rc; -use std::sync::Arc; use std::u32; use syntax::ast::{self, CRATE_NODE_ID}; use syntax::codemap::Spanned; @@ -284,7 +282,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let codemap = self.tcx.sess.codemap(); let all_filemaps = codemap.files(); - let hcx = &mut StableHashingContext::new(self.tcx); let (working_dir, working_dir_was_remapped) = self.tcx.sess.working_dir.clone(); let adapted = all_filemaps.iter() @@ -316,21 +313,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { adapted.name = abs_path; Rc::new(adapted) } - }); - - let filemaps: Vec<_> = if self.compute_ich { - adapted.inspect(|filemap| { - let mut hasher = StableHasher::new(); - filemap.hash_stable(hcx, &mut hasher); - let fingerprint = hasher.finish(); - let dep_node = DepNode::FileMap((), Arc::new(filemap.name.clone())); - self.metadata_hashes.global_hashes.push((dep_node, fingerprint)); - }).collect() - } else { - adapted.collect() - }; + }) + .collect::>(); - self.lazy_seq_ref(filemaps.iter().map(|fm| &**fm)) + self.lazy_seq_ref(adapted.iter().map(|rc| &**rc)) } fn encode_crate_root(&mut self) -> Lazy { diff --git a/src/librustc_metadata/isolated_encoder.rs b/src/librustc_metadata/isolated_encoder.rs index 7722a7b10c996..ed1680fbfaee8 100644 --- a/src/librustc_metadata/isolated_encoder.rs +++ b/src/librustc_metadata/isolated_encoder.rs @@ -35,7 +35,17 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { tcx: tcx, ecx: ecx, hcx: if compute_ich { - Some((StableHashingContext::new(tcx), StableHasher::new())) + // We are always hashing spans for things in metadata because + // don't know if a downstream crate will use them or not. + // Except when -Zquery-dep-graph is specified because we don't + // want to mess up our tests. + let hcx = if tcx.sess.opts.debugging_opts.query_dep_graph { + StableHashingContext::new(tcx) + } else { + StableHashingContext::new(tcx).force_span_hashing() + }; + + Some((hcx, StableHasher::new())) } else { None } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index d32c3ec5f46b1..bbe5bd4a10cf1 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -103,18 +103,11 @@ impl FileLoader for RealFileLoader { // pub struct CodeMap { - // The `files` field should not be visible outside of libsyntax so that we - // can do proper dependency tracking. pub(super) files: RefCell>>, file_loader: Box, // This is used to apply the file path remapping as specified via // -Zremap-path-prefix to all FileMaps allocated within this CodeMap. path_mapping: FilePathMapping, - // The CodeMap will invoke this callback whenever a specific FileMap is - // accessed. The callback starts out as a no-op but when the dependency - // graph becomes available later during the compilation process, it is - // be replaced with something that notifies the dep-tracking system. - dep_tracking_callback: RefCell>, } impl CodeMap { @@ -123,7 +116,6 @@ impl CodeMap { files: RefCell::new(Vec::new()), file_loader: Box::new(RealFileLoader), path_mapping: path_mapping, - dep_tracking_callback: RefCell::new(Box::new(|_| {})), } } @@ -134,7 +126,6 @@ impl CodeMap { files: RefCell::new(Vec::new()), file_loader: file_loader, path_mapping: path_mapping, - dep_tracking_callback: RefCell::new(Box::new(|_| {})), } } @@ -142,10 +133,6 @@ impl CodeMap { &self.path_mapping } - pub fn set_dep_tracking_callback(&self, cb: Box) { - *self.dep_tracking_callback.borrow_mut() = cb; - } - pub fn file_exists(&self, path: &Path) -> bool { self.file_loader.file_exists(path) } @@ -156,15 +143,6 @@ impl CodeMap { } pub fn files(&self) -> Ref>> { - let files = self.files.borrow(); - for file in files.iter() { - (self.dep_tracking_callback.borrow())(file); - } - files - } - - /// Only use this if you do your own dependency tracking! - pub fn files_untracked(&self) -> Ref>> { self.files.borrow() } @@ -311,8 +289,6 @@ impl CodeMap { let files = self.files.borrow(); let f = (*files)[idx].clone(); - (self.dep_tracking_callback.borrow())(&f); - match f.lookup_line(pos) { Some(line) => Ok(FileMapAndLine { fm: f, line: line }), None => Err(f) @@ -502,7 +478,6 @@ impl CodeMap { pub fn get_filemap(&self, filename: &str) -> Option> { for fm in self.files.borrow().iter() { if filename == fm.name { - (self.dep_tracking_callback.borrow())(fm); return Some(fm.clone()); } } @@ -513,7 +488,6 @@ impl CodeMap { pub fn lookup_byte_offset(&self, bpos: BytePos) -> FileMapAndBytePos { let idx = self.lookup_filemap_idx(bpos); let fm = (*self.files.borrow())[idx].clone(); - (self.dep_tracking_callback.borrow())(&fm); let offset = bpos - fm.start_pos; FileMapAndBytePos {fm: fm, pos: offset} } @@ -524,8 +498,6 @@ impl CodeMap { let files = self.files.borrow(); let map = &(*files)[idx]; - (self.dep_tracking_callback.borrow())(map); - // The number of extra bytes due to multibyte chars in the FileMap let mut total_extra_bytes = 0; diff --git a/src/test/incremental/rlib_cross_crate/auxiliary/a.rs b/src/test/incremental/rlib_cross_crate/auxiliary/a.rs index ff5fd63471449..1099aeb921763 100644 --- a/src/test/incremental/rlib_cross_crate/auxiliary/a.rs +++ b/src/test/incremental/rlib_cross_crate/auxiliary/a.rs @@ -9,6 +9,7 @@ // except according to those terms. // no-prefer-dynamic +// compile-flags: -Z query-dep-graph #![crate_type="rlib"] diff --git a/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs b/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs index e1dba1317703d..2ae434071f2c5 100644 --- a/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs +++ b/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z query-dep-graph + #![crate_type="rlib"] #[cfg(rpass1)] From fb9ca16b3b7cf034f885de28879c4d50261ce3ef Mon Sep 17 00:00:00 2001 From: Paul Faria Date: Tue, 23 May 2017 21:51:21 -0400 Subject: [PATCH 07/13] Remove all instances of fragment_infos and fragment sets --- src/librustc/ty/context.rs | 30 +- src/librustc/ty/mod.rs | 11 - src/librustc_borrowck/borrowck/fragments.rs | 542 -------------------- src/librustc_borrowck/borrowck/mod.rs | 7 - src/librustc_borrowck/borrowck/move_data.rs | 19 - 5 files changed, 1 insertion(+), 608 deletions(-) delete mode 100644 src/librustc_borrowck/borrowck/fragments.rs diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 5ee0b1c9e5ea4..64e16c41d1132 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -40,7 +40,7 @@ use ty::layout::{Layout, TargetDataLayout}; use ty::inhabitedness::DefIdForest; use ty::maps; use ty::steal::Steal; -use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet}; +use util::nodemap::{NodeMap, NodeSet, DefIdSet}; use util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::accumulate_vec::AccumulateVec; @@ -499,33 +499,6 @@ pub struct GlobalCtxt<'tcx> { /// Maps Expr NodeId's to `true` iff `&expr` can have 'static lifetime. pub rvalue_promotable_to_static: RefCell>, - /// Maps Fn items to a collection of fragment infos. - /// - /// The main goal is to identify data (each of which may be moved - /// or assigned) whose subparts are not moved nor assigned - /// (i.e. their state is *unfragmented*) and corresponding ast - /// nodes where the path to that data is moved or assigned. - /// - /// In the long term, unfragmented values will have their - /// destructor entirely driven by a single stack-local drop-flag, - /// and their parents, the collections of the unfragmented values - /// (or more simply, "fragmented values"), are mapped to the - /// corresponding collections of stack-local drop-flags. - /// - /// (However, in the short term that is not the case; e.g. some - /// unfragmented paths still need to be zeroed, namely when they - /// reference parent data from an outer scope that was not - /// entirely moved, and therefore that needs to be zeroed so that - /// we do not get double-drop when we hit the end of the parent - /// scope.) - /// - /// Also: currently the table solely holds keys for node-ids of - /// unfragmented values (see `FragmentInfo` enum definition), but - /// longer-term we will need to also store mappings from - /// fragmented data to the set of unfragmented pieces that - /// constitute it. - pub fragment_infos: RefCell>>, - /// The definite name of the current crate after taking into account /// attributes, commandline parameters, etc. pub crate_name: Symbol, @@ -730,7 +703,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { selection_cache: traits::SelectionCache::new(), evaluation_cache: traits::EvaluationCache::new(), rvalue_promotable_to_static: RefCell::new(NodeMap()), - fragment_infos: RefCell::new(DefIdMap()), crate_name: Symbol::intern(crate_name), data_layout: data_layout, layout_cache: RefCell::new(FxHashMap()), diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index fa731f6dde638..cd72ac53583ce 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -443,17 +443,6 @@ pub struct CReaderCacheKey { pub pos: usize, } -/// Describes the fragment-state associated with a NodeId. -/// -/// Currently only unfragmented paths have entries in the table, -/// but longer-term this enum is expected to expand to also -/// include data for fragmented paths. -#[derive(Copy, Clone, Debug)] -pub enum FragmentInfo { - Moved { var: NodeId, move_expr: NodeId }, - Assigned { var: NodeId, assign_expr: NodeId, assignee_id: NodeId }, -} - // Flags that we track on types. These flags are propagated upwards // through the type during type construction, so that we can quickly // check whether the type has various kinds of types in it without diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs deleted file mode 100644 index b728d4d534516..0000000000000 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ /dev/null @@ -1,542 +0,0 @@ -// Copyright 2012-2014 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. - -//! Helper routines used for fragmenting structural paths due to moves for -//! tracking drop obligations. Please see the extensive comments in the -//! section "Structural fragments" in `README.md`. - -use self::Fragment::*; - -use borrowck::InteriorKind::{InteriorField, InteriorElement}; -use borrowck::{self, LoanPath}; -use borrowck::LoanPathKind::{LpVar, LpUpvar, LpDowncast, LpExtend}; -use borrowck::LoanPathElem::{LpDeref, LpInterior}; -use borrowck::move_data::InvalidMovePathIndex; -use borrowck::move_data::{MoveData, MovePathIndex}; -use rustc::hir::def_id::{DefId}; -use rustc::ty::{self, AdtKind, TyCtxt}; -use rustc::middle::mem_categorization as mc; - -use std::mem; -use std::rc::Rc; -use syntax::ast; -use syntax_pos::DUMMY_SP; - -#[derive(PartialEq, Eq, PartialOrd, Ord)] -enum Fragment { - // This represents the path described by the move path index - Just(MovePathIndex), - - // This represents the collection of all but one of the elements - // from an array at the path described by the move path index. - // Note that attached MovePathIndex should have mem_categorization - // of InteriorElement (i.e. array dereference `&foo[..]`). - AllButOneFrom(MovePathIndex), -} - -impl Fragment { - fn loan_path_repr(&self, move_data: &MoveData) -> String { - let lp = |mpi| move_data.path_loan_path(mpi); - match *self { - Just(mpi) => format!("{:?}", lp(mpi)), - AllButOneFrom(mpi) => format!("$(allbutone {:?})", lp(mpi)), - } - } - - fn loan_path_user_string(&self, move_data: &MoveData) -> String { - let lp = |mpi| move_data.path_loan_path(mpi); - match *self { - Just(mpi) => lp(mpi).to_string(), - AllButOneFrom(mpi) => format!("$(allbutone {})", lp(mpi)), - } - } -} - -pub fn build_unfragmented_map(this: &mut borrowck::BorrowckCtxt, - move_data: &MoveData, - id: ast::NodeId) { - let fr = &move_data.fragments.borrow(); - - // For now, don't care about other kinds of fragments; the precise - // classfication of all paths for non-zeroing *drop* needs them, - // but the loose approximation used by non-zeroing moves does not. - let moved_leaf_paths = fr.moved_leaf_paths(); - let assigned_leaf_paths = fr.assigned_leaf_paths(); - - let mut fragment_infos = Vec::with_capacity(moved_leaf_paths.len()); - - let find_var_id = |move_path_index: MovePathIndex| -> Option { - let lp = move_data.path_loan_path(move_path_index); - match lp.kind { - LpVar(var_id) => Some(var_id), - LpUpvar(ty::UpvarId { var_id, closure_expr_id }) => { - // The `var_id` is unique *relative to* the current function. - // (Check that we are indeed talking about the same function.) - assert_eq!(id, closure_expr_id); - Some(var_id) - } - LpDowncast(..) | LpExtend(..) => { - // This simple implementation of non-zeroing move does - // not attempt to deal with tracking substructure - // accurately in the general case. - None - } - } - }; - - let moves = move_data.moves.borrow(); - for &move_path_index in moved_leaf_paths { - let var_id = match find_var_id(move_path_index) { - None => continue, - Some(var_id) => var_id, - }; - - move_data.each_applicable_move(move_path_index, |move_index| { - let info = ty::FragmentInfo::Moved { - var: var_id, - move_expr: moves[move_index.get()].id, - }; - debug!("fragment_infos push({:?} \ - due to move_path_index: {} move_index: {}", - info, move_path_index.get(), move_index.get()); - fragment_infos.push(info); - true - }); - } - - for &move_path_index in assigned_leaf_paths { - let var_id = match find_var_id(move_path_index) { - None => continue, - Some(var_id) => var_id, - }; - - let var_assigns = move_data.var_assignments.borrow(); - for var_assign in var_assigns.iter() - .filter(|&assign| assign.path == move_path_index) - { - let info = ty::FragmentInfo::Assigned { - var: var_id, - assign_expr: var_assign.id, - assignee_id: var_assign.assignee_id, - }; - debug!("fragment_infos push({:?} due to var_assignment", info); - fragment_infos.push(info); - } - } - - let mut fraginfo_map = this.tcx.fragment_infos.borrow_mut(); - let fn_did = this.tcx.hir.local_def_id(id); - let prev = fraginfo_map.insert(fn_did, fragment_infos); - assert!(prev.is_none()); -} - -pub struct FragmentSets { - /// During move_data construction, `moved_leaf_paths` tracks paths - /// that have been used directly by being moved out of. When - /// move_data construction has been completed, `moved_leaf_paths` - /// tracks such paths that are *leaf fragments* (e.g. `a.j` if we - /// never move out any child like `a.j.x`); any parent paths - /// (e.g. `a` for the `a.j` example) are moved over to - /// `parents_of_fragments`. - moved_leaf_paths: Vec, - - /// `assigned_leaf_paths` tracks paths that have been used - /// directly by being overwritten, but is otherwise much like - /// `moved_leaf_paths`. - assigned_leaf_paths: Vec, - - /// `parents_of_fragments` tracks paths that are definitely - /// parents of paths that have been moved. - /// - /// FIXME(pnkfelix) probably do not want/need - /// `parents_of_fragments` at all, if we can avoid it. - /// - /// Update: I do not see a way to avoid it. Maybe just remove - /// above fixme, or at least document why doing this may be hard. - parents_of_fragments: Vec, - - /// During move_data construction (specifically the - /// fixup_fragment_sets call), `unmoved_fragments` tracks paths - /// that have been "left behind" after a sibling has been moved or - /// assigned. When move_data construction has been completed, - /// `unmoved_fragments` tracks paths that were *only* results of - /// being left-behind, and never directly moved themselves. - unmoved_fragments: Vec, -} - -impl FragmentSets { - pub fn new() -> FragmentSets { - FragmentSets { - unmoved_fragments: Vec::new(), - moved_leaf_paths: Vec::new(), - assigned_leaf_paths: Vec::new(), - parents_of_fragments: Vec::new(), - } - } - - pub fn moved_leaf_paths(&self) -> &[MovePathIndex] { - &self.moved_leaf_paths - } - - pub fn assigned_leaf_paths(&self) -> &[MovePathIndex] { - &self.assigned_leaf_paths - } - - pub fn add_move(&mut self, path_index: MovePathIndex) { - self.moved_leaf_paths.push(path_index); - } - - pub fn add_assignment(&mut self, path_index: MovePathIndex) { - self.assigned_leaf_paths.push(path_index); - } -} - -pub fn instrument_move_fragments<'a, 'tcx>(this: &MoveData<'tcx>, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: ast::NodeId) { - let span_err = tcx.hir.attrs(id).iter() - .any(|a| a.check_name("rustc_move_fragments")); - let print = tcx.sess.opts.debugging_opts.print_move_fragments; - - if !span_err && !print { return; } - - let sp = tcx.hir.span(id); - - let instrument_all_paths = |kind, vec_rc: &Vec| { - for (i, mpi) in vec_rc.iter().enumerate() { - let lp = || this.path_loan_path(*mpi); - if span_err { - tcx.sess.span_err(sp, &format!("{}: `{}`", kind, lp())); - } - if print { - println!("id:{} {}[{}] `{}`", id, kind, i, lp()); - } - } - }; - - let instrument_all_fragments = |kind, vec_rc: &Vec| { - for (i, f) in vec_rc.iter().enumerate() { - let render = || f.loan_path_user_string(this); - if span_err { - tcx.sess.span_err(sp, &format!("{}: `{}`", kind, render())); - } - if print { - println!("id:{} {}[{}] `{}`", id, kind, i, render()); - } - } - }; - - let fragments = this.fragments.borrow(); - instrument_all_paths("moved_leaf_path", &fragments.moved_leaf_paths); - instrument_all_fragments("unmoved_fragment", &fragments.unmoved_fragments); - instrument_all_paths("parent_of_fragments", &fragments.parents_of_fragments); - instrument_all_paths("assigned_leaf_path", &fragments.assigned_leaf_paths); -} - -/// Normalizes the fragment sets in `this`; i.e., removes duplicate entries, constructs the set of -/// parents, and constructs the left-over fragments. -/// -/// Note: "left-over fragments" means paths that were not directly referenced in moves nor -/// assignments, but must nonetheless be tracked as potential drop obligations. -pub fn fixup_fragment_sets<'a, 'tcx>(this: &MoveData<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) { - - let mut fragments = this.fragments.borrow_mut(); - - // Swap out contents of fragments so that we can modify the fields - // without borrowing the common fragments. - let mut unmoved = mem::replace(&mut fragments.unmoved_fragments, vec![]); - let mut parents = mem::replace(&mut fragments.parents_of_fragments, vec![]); - let mut moved = mem::replace(&mut fragments.moved_leaf_paths, vec![]); - let mut assigned = mem::replace(&mut fragments.assigned_leaf_paths, vec![]); - - let path_lps = |mpis: &[MovePathIndex]| -> Vec { - mpis.iter().map(|mpi| format!("{:?}", this.path_loan_path(*mpi))).collect() - }; - - let frag_lps = |fs: &[Fragment]| -> Vec { - fs.iter().map(|f| f.loan_path_repr(this)).collect() - }; - - // First, filter out duplicates - moved.sort(); - moved.dedup(); - debug!("fragments 1 moved: {:?}", path_lps(&moved)); - - assigned.sort(); - assigned.dedup(); - debug!("fragments 1 assigned: {:?}", path_lps(&assigned)); - - // Second, build parents from the moved and assigned. - for m in &moved { - let mut p = this.path_parent(*m); - while p != InvalidMovePathIndex { - parents.push(p); - p = this.path_parent(p); - } - } - for a in &assigned { - let mut p = this.path_parent(*a); - while p != InvalidMovePathIndex { - parents.push(p); - p = this.path_parent(p); - } - } - - parents.sort(); - parents.dedup(); - debug!("fragments 2 parents: {:?}", path_lps(&parents)); - - // Third, filter the moved and assigned fragments down to just the non-parents - moved.retain(|f| non_member(*f, &parents)); - debug!("fragments 3 moved: {:?}", path_lps(&moved)); - - assigned.retain(|f| non_member(*f, &parents)); - debug!("fragments 3 assigned: {:?}", path_lps(&assigned)); - - // Fourth, build the leftover from the moved, assigned, and parents. - for m in &moved { - let lp = this.path_loan_path(*m); - add_fragment_siblings(this, tcx, &mut unmoved, lp, None); - } - for a in &assigned { - let lp = this.path_loan_path(*a); - add_fragment_siblings(this, tcx, &mut unmoved, lp, None); - } - for p in &parents { - let lp = this.path_loan_path(*p); - add_fragment_siblings(this, tcx, &mut unmoved, lp, None); - } - - unmoved.sort(); - unmoved.dedup(); - debug!("fragments 4 unmoved: {:?}", frag_lps(&unmoved)); - - // Fifth, filter the leftover fragments down to its core. - unmoved.retain(|f| match *f { - AllButOneFrom(_) => true, - Just(mpi) => non_member(mpi, &parents) && - non_member(mpi, &moved) && - non_member(mpi, &assigned) - }); - debug!("fragments 5 unmoved: {:?}", frag_lps(&unmoved)); - - // Swap contents back in. - fragments.unmoved_fragments = unmoved; - fragments.parents_of_fragments = parents; - fragments.moved_leaf_paths = moved; - fragments.assigned_leaf_paths = assigned; - - return; - - fn non_member(elem: MovePathIndex, set: &[MovePathIndex]) -> bool { - match set.binary_search(&elem) { - Ok(_) => false, - Err(_) => true, - } - } -} - -/// Adds all of the precisely-tracked siblings of `lp` as potential move paths of interest. For -/// example, if `lp` represents `s.x.j`, then adds moves paths for `s.x.i` and `s.x.k`, the -/// siblings of `s.x.j`. -fn add_fragment_siblings<'a, 'tcx>(this: &MoveData<'tcx>, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - gathered_fragments: &mut Vec, - lp: Rc>, - origin_id: Option) { - match lp.kind { - LpVar(_) | LpUpvar(..) => {} // Local variables have no siblings. - - // Consuming a downcast is like consuming the original value, so propage inward. - LpDowncast(ref loan_parent, _) => { - add_fragment_siblings(this, tcx, gathered_fragments, loan_parent.clone(), origin_id); - } - - // *LV for Unique consumes the contents of the box (at - // least when it is non-copy...), so propagate inward. - LpExtend(ref loan_parent, _, LpDeref(mc::Unique)) => { - add_fragment_siblings(this, tcx, gathered_fragments, loan_parent.clone(), origin_id); - } - - // *LV for unsafe and borrowed pointers do not consume their loan path, so stop here. - LpExtend(.., LpDeref(mc::UnsafePtr(..))) | - LpExtend(.., LpDeref(mc::Implicit(..))) | - LpExtend(.., LpDeref(mc::BorrowedPtr(..))) => {} - - // FIXME (pnkfelix): LV[j] should be tracked, at least in the - // sense of we will track the remaining drop obligation of the - // rest of the array. - // - // Well, either that or LV[j] should be made illegal. - // But even then, we will need to deal with destructuring - // bind. - // - // Anyway, for now: LV[j] is not tracked precisely - LpExtend(.., LpInterior(_, InteriorElement(..))) => { - let mp = this.move_path(tcx, lp.clone()); - gathered_fragments.push(AllButOneFrom(mp)); - } - - // field access LV.x and tuple access LV#k are the cases - // we are interested in - LpExtend(ref loan_parent, mc, - LpInterior(_, InteriorField(ref field_name))) => { - let enum_variant_info = match loan_parent.kind { - LpDowncast(ref loan_parent_2, variant_def_id) => - Some((variant_def_id, loan_parent_2.clone())), - LpExtend(..) | LpVar(..) | LpUpvar(..) => - None, - }; - add_fragment_siblings_for_extension( - this, - tcx, - gathered_fragments, - loan_parent, mc, field_name, &lp, origin_id, enum_variant_info); - } - } -} - -/// We have determined that `origin_lp` destructures to LpExtend(parent, original_field_name). -/// Based on this, add move paths for all of the siblings of `origin_lp`. -fn add_fragment_siblings_for_extension<'a, 'tcx>(this: &MoveData<'tcx>, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - gathered_fragments: &mut Vec, - parent_lp: &Rc>, - mc: mc::MutabilityCategory, - origin_field_name: &mc::FieldName, - origin_lp: &Rc>, - origin_id: Option, - enum_variant_info: Option<(DefId, - Rc>)>) { - let parent_ty = parent_lp.to_type(); - - let mut add_fragment_sibling_local = |field_name, variant_did| { - add_fragment_sibling_core( - this, tcx, gathered_fragments, parent_lp.clone(), mc, field_name, origin_lp, - variant_did); - }; - - match parent_ty.sty { - ty::TyTuple(ref v, _) => { - let tuple_idx = match *origin_field_name { - mc::PositionalField(tuple_idx) => tuple_idx, - mc::NamedField(_) => - bug!("tuple type {:?} should not have named fields.", - parent_ty), - }; - let tuple_len = v.len(); - for i in 0..tuple_len { - if i == tuple_idx { continue } - let field_name = mc::PositionalField(i); - add_fragment_sibling_local(field_name, None); - } - } - - ty::TyAdt(def, ..) => match def.adt_kind() { - AdtKind::Struct => { - match *origin_field_name { - mc::NamedField(ast_name) => { - for f in &def.struct_variant().fields { - if f.name == ast_name { - continue; - } - let field_name = mc::NamedField(f.name); - add_fragment_sibling_local(field_name, None); - } - } - mc::PositionalField(tuple_idx) => { - for (i, _f) in def.struct_variant().fields.iter().enumerate() { - if i == tuple_idx { - continue - } - let field_name = mc::PositionalField(i); - add_fragment_sibling_local(field_name, None); - } - } - } - } - AdtKind::Union => { - // Do nothing, all union fields are moved/assigned together. - } - AdtKind::Enum => { - let variant = match enum_variant_info { - Some((vid, ref _lp2)) => def.variant_with_id(vid), - None => { - assert!(def.is_univariant()); - &def.variants[0] - } - }; - match *origin_field_name { - mc::NamedField(ast_name) => { - for field in &variant.fields { - if field.name == ast_name { - continue; - } - let field_name = mc::NamedField(field.name); - add_fragment_sibling_local(field_name, Some(variant.did)); - } - } - mc::PositionalField(tuple_idx) => { - for (i, _f) in variant.fields.iter().enumerate() { - if tuple_idx == i { - continue; - } - let field_name = mc::PositionalField(i); - add_fragment_sibling_local(field_name, None); - } - } - } - } - }, - - ref ty => { - let span = origin_id.map_or(DUMMY_SP, |id| tcx.hir.span(id)); - span_bug!(span, - "type {:?} ({:?}) is not fragmentable", - parent_ty, ty); - } - } -} - -/// Adds the single sibling `LpExtend(parent, new_field_name)` of `origin_lp` (the original -/// loan-path). -fn add_fragment_sibling_core<'a, 'tcx>(this: &MoveData<'tcx>, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - gathered_fragments: &mut Vec, - parent: Rc>, - mc: mc::MutabilityCategory, - new_field_name: mc::FieldName, - origin_lp: &Rc>, - enum_variant_did: Option) - -> MovePathIndex { - let opt_variant_did = match parent.kind { - LpDowncast(_, variant_did) => Some(variant_did), - LpVar(..) | LpUpvar(..) | LpExtend(..) => enum_variant_did, - }; - - let loan_path_elem = LpInterior(opt_variant_did, InteriorField(new_field_name)); - let new_lp_type = match new_field_name { - mc::NamedField(ast_name) => - tcx.named_element_ty(parent.to_type(), ast_name, opt_variant_did), - mc::PositionalField(idx) => - tcx.positional_element_ty(parent.to_type(), idx, opt_variant_did), - }; - let new_lp_variant = LpExtend(parent, mc, loan_path_elem); - let new_lp = LoanPath::new(new_lp_variant, new_lp_type.unwrap()); - debug!("add_fragment_sibling_core(new_lp={:?}, origin_lp={:?})", - new_lp, origin_lp); - let mp = this.move_path(tcx, Rc::new(new_lp)); - - // Do not worry about checking for duplicates here; we will sort - // and dedup after all are added. - gathered_fragments.push(Just(mp)); - - mp -} diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index f7c20542cbf2e..ff5ebb9c1dc5d 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -129,13 +129,6 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) { move_data: flowed_moves } = build_borrowck_dataflow_data(bccx, &cfg, body_id); - move_data::fragments::instrument_move_fragments(&flowed_moves.move_data, - bccx.tcx, - owner_id); - move_data::fragments::build_unfragmented_map(bccx, - &flowed_moves.move_data, - owner_id); - check_loans::check_loans(bccx, &loan_dfcx, &flowed_moves, &all_loans, body); } diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index 3e23086ec7bdd..1b364596a23f7 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -33,9 +33,6 @@ use syntax_pos::Span; use rustc::hir; use rustc::hir::intravisit::IdRange; -#[path="fragments.rs"] -pub mod fragments; - pub struct MoveData<'tcx> { /// Move paths. See section "Move paths" in `README.md`. pub paths: RefCell>>, @@ -62,9 +59,6 @@ pub struct MoveData<'tcx> { /// Assignments to a variable or path, like `x = foo`, but not `x += foo`. pub assignee_ids: RefCell, - - /// Path-fragments from moves in to or out of parts of structured data. - pub fragments: RefCell, } pub struct FlowedMoveData<'a, 'tcx: 'a> { @@ -223,7 +217,6 @@ impl<'a, 'tcx> MoveData<'tcx> { var_assignments: RefCell::new(Vec::new()), variant_matches: RefCell::new(Vec::new()), assignee_ids: RefCell::new(NodeSet()), - fragments: RefCell::new(fragments::FragmentSets::new()), } } @@ -401,8 +394,6 @@ impl<'a, 'tcx> MoveData<'tcx> { let path_index = self.move_path(tcx, lp.clone()); let move_index = MoveIndex(self.moves.borrow().len()); - self.fragments.borrow_mut().add_move(path_index); - let next_move = self.path_first_move(path_index); self.set_path_first_move(path_index, move_index); @@ -458,8 +449,6 @@ impl<'a, 'tcx> MoveData<'tcx> { let path_index = self.move_path(tcx, lp.clone()); - self.fragments.borrow_mut().add_assignment(path_index); - match mode { MutateMode::Init | MutateMode::JustWrite => { self.assignee_ids.borrow_mut().insert(assignee_id); @@ -502,8 +491,6 @@ impl<'a, 'tcx> MoveData<'tcx> { let path_index = self.move_path(tcx, lp.clone()); let base_path_index = self.move_path(tcx, base_lp.clone()); - self.fragments.borrow_mut().add_assignment(path_index); - let variant_match = VariantMatch { path: path_index, base_path: base_path_index, @@ -514,10 +501,6 @@ impl<'a, 'tcx> MoveData<'tcx> { self.variant_matches.borrow_mut().push(variant_match); } - fn fixup_fragment_sets(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) { - fragments::fixup_fragment_sets(self, tcx) - } - /// Adds the gen/kills for the various moves and /// assignments into the provided data flow contexts. /// Moves are generated by moves and killed by assignments and @@ -677,8 +660,6 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> { id_range, move_data.var_assignments.borrow().len()); - move_data.fixup_fragment_sets(tcx); - move_data.add_gen_kills(bccx, &mut dfcx_moves, &mut dfcx_assign); From 87950b79de4bd12ad02f32dbebc60ab1bef17f82 Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 23 May 2017 02:28:13 +0200 Subject: [PATCH 08/13] Stabilize non capturing closure to fn coercion --- src/doc/unstable-book/src/SUMMARY.md | 1 - .../closure-to-fn-coercion.md | 7 --- src/librustc_typeck/check/coercion.rs | 9 ---- src/libsyntax/feature_gate.rs | 8 +--- .../feature-gate-closure_to_fn_coercion.rs | 45 ------------------- src/test/compile-fail/issue-40000.rs | 2 - src/test/run-pass/closure-to-fn-coercion.rs | 4 -- .../closure_to_fn_coercion-expected-types.rs | 1 - 8 files changed, 2 insertions(+), 75 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/closure-to-fn-coercion.md delete mode 100644 src/test/compile-fail/feature-gate-closure_to_fn_coercion.rs diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 028f5c9ee5aaf..2058d4be17eb2 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -24,7 +24,6 @@ - [cfg_target_has_atomic](language-features/cfg-target-has-atomic.md) - [cfg_target_thread_local](language-features/cfg-target-thread-local.md) - [cfg_target_vendor](language-features/cfg-target-vendor.md) - - [closure_to_fn_coercion](language-features/closure-to-fn-coercion.md) - [compiler_builtins](language-features/compiler-builtins.md) - [concat_idents](language-features/concat-idents.md) - [conservative_impl_trait](language-features/conservative-impl-trait.md) diff --git a/src/doc/unstable-book/src/language-features/closure-to-fn-coercion.md b/src/doc/unstable-book/src/language-features/closure-to-fn-coercion.md deleted file mode 100644 index 4e3b735e24fb6..0000000000000 --- a/src/doc/unstable-book/src/language-features/closure-to-fn-coercion.md +++ /dev/null @@ -1,7 +0,0 @@ -# `closure_to_fn_coercion` - -The tracking issue for this feature is: [#39817] - -[#39817]: https://github.com/rust-lang/rust/issues/39817 - ------------------------- diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index c228fc6b24abd..883a0a9d88a1c 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -76,7 +76,6 @@ use rustc::ty::relate::RelateResult; use rustc::ty::subst::Subst; use errors::DiagnosticBuilder; use syntax::abi; -use syntax::feature_gate; use syntax::ptr::P; use syntax_pos; @@ -614,14 +613,6 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let node_id_a = self.tcx.hir.as_local_node_id(def_id_a).unwrap(); match b.sty { ty::TyFnPtr(_) if self.tcx.with_freevars(node_id_a, |v| v.is_empty()) => { - if !self.tcx.sess.features.borrow().closure_to_fn_coercion { - feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, - "closure_to_fn_coercion", - self.cause.span, - feature_gate::GateIssue::Language, - feature_gate::CLOSURE_TO_FN_COERCION); - return self.unify_and(a, b, identity()); - } // We coerce the closure, which has fn type // `extern "rust-call" fn((arg0,arg1,...)) -> _` // to diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 6acf27f314ab5..70ab2e8dfe7a0 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -318,9 +318,6 @@ declare_features! ( // `extern "msp430-interrupt" fn()` (active, abi_msp430_interrupt, "1.16.0", Some(38487)), - // Coerces non capturing closures to function pointers - (active, closure_to_fn_coercion, "1.17.0", Some(39817)), - // Used to identify crates that contain sanitizer runtimes // rustc internal (active, sanitizer_runtime, "1.17.0", None), @@ -421,6 +418,8 @@ declare_features! ( (accepted, loop_break_value, "1.19.0", Some(37339)), // Permits numeric fields in struct expressions and patterns. (accepted, relaxed_adts, "1.19.0", Some(35626)), + // Coerces non capturing closures to function pointers + (accepted, closure_to_fn_coercion, "1.19.0", Some(39817)), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -1020,9 +1019,6 @@ pub const EXPLAIN_VIS_MATCHER: &'static str = pub const EXPLAIN_PLACEMENT_IN: &'static str = "placement-in expression syntax is experimental and subject to change."; -pub const CLOSURE_TO_FN_COERCION: &'static str = - "non-capturing closure to fn coercion is experimental"; - struct PostExpansionVisitor<'a> { context: &'a Context<'a>, } diff --git a/src/test/compile-fail/feature-gate-closure_to_fn_coercion.rs b/src/test/compile-fail/feature-gate-closure_to_fn_coercion.rs deleted file mode 100644 index d074a35628ea8..0000000000000 --- a/src/test/compile-fail/feature-gate-closure_to_fn_coercion.rs +++ /dev/null @@ -1,45 +0,0 @@ -// 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. - -// ignore-stage0: new feature, remove this when SNAP -// revisions: a b - -#[cfg(a)] -mod a { - const FOO: fn(u8) -> u8 = |v: u8| { v }; - //[a]~^ ERROR non-capturing closure to fn coercion is experimental - //[a]~^^ ERROR mismatched types - - const BAR: [fn(&mut u32); 1] = [ - |v: &mut u32| *v += 1, - //[a]~^ ERROR non-capturing closure to fn coercion is experimental - //[a]~^^ ERROR mismatched types - ]; -} - -#[cfg(b)] -mod b { - fn func_specific() -> (fn() -> u32) { - || return 42 - //[b]~^ ERROR non-capturing closure to fn coercion is experimental - //[b]~^^ ERROR mismatched types - } - fn foo() { - // Items - assert_eq!(func_specific()(), 42); - let foo: fn(u8) -> u8 = |v: u8| { v }; - //[b]~^ ERROR non-capturing closure to fn coercion is experimental - //[b]~^^ ERROR mismatched types - } - -} - - - diff --git a/src/test/compile-fail/issue-40000.rs b/src/test/compile-fail/issue-40000.rs index 3ccee0f12becb..7daf4bcbaa44b 100644 --- a/src/test/compile-fail/issue-40000.rs +++ b/src/test/compile-fail/issue-40000.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(closure_to_fn_coercion)] - fn main() { let bar: fn(&mut u32) = |_| {}; diff --git a/src/test/run-pass/closure-to-fn-coercion.rs b/src/test/run-pass/closure-to-fn-coercion.rs index 13d1d6aa13900..7fb26bdc9360d 100644 --- a/src/test/run-pass/closure-to-fn-coercion.rs +++ b/src/test/run-pass/closure-to-fn-coercion.rs @@ -8,10 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-stage0: new feature, remove this when SNAP - -#![feature(closure_to_fn_coercion)] - const FOO: fn(u8) -> u8 = |v: u8| { v }; const BAR: [fn(&mut u32); 5] = [ diff --git a/src/test/run-pass/closure_to_fn_coercion-expected-types.rs b/src/test/run-pass/closure_to_fn_coercion-expected-types.rs index 7214ebfaf0703..41da3089c884e 100644 --- a/src/test/run-pass/closure_to_fn_coercion-expected-types.rs +++ b/src/test/run-pass/closure_to_fn_coercion-expected-types.rs @@ -9,7 +9,6 @@ // except according to those terms. // Ensure that we deduce expected argument types when a `fn()` type is expected (#41755) -#![feature(closure_to_fn_coercion)] fn foo(f: fn(Vec) -> usize) { } fn main() { From a563f350b0122da51a507037956858639b2aa106 Mon Sep 17 00:00:00 2001 From: Paul Faria Date: Thu, 25 May 2017 07:59:13 -0400 Subject: [PATCH 09/13] Remove irrelevant tests and unused testing attribute --- src/libsyntax/feature_gate.rs | 6 -- .../compile-fail/feature-gate-rustc-attrs.rs | 1 - src/test/compile-fail/move-fragments-1.rs | 58 ------------ src/test/compile-fail/move-fragments-2.rs | 87 ----------------- src/test/compile-fail/move-fragments-3.rs | 49 ---------- src/test/compile-fail/move-fragments-4.rs | 41 -------- src/test/compile-fail/move-fragments-5.rs | 94 ------------------- src/test/compile-fail/move-fragments-6.rs | 61 ------------ src/test/compile-fail/move-fragments-7.rs | 48 ---------- src/test/compile-fail/move-fragments-8.rs | 41 -------- src/test/compile-fail/move-fragments-9.rs | 49 ---------- 11 files changed, 535 deletions(-) delete mode 100644 src/test/compile-fail/move-fragments-1.rs delete mode 100644 src/test/compile-fail/move-fragments-2.rs delete mode 100644 src/test/compile-fail/move-fragments-3.rs delete mode 100644 src/test/compile-fail/move-fragments-4.rs delete mode 100644 src/test/compile-fail/move-fragments-5.rs delete mode 100644 src/test/compile-fail/move-fragments-6.rs delete mode 100644 src/test/compile-fail/move-fragments-7.rs delete mode 100644 src/test/compile-fail/move-fragments-8.rs delete mode 100644 src/test/compile-fail/move-fragments-9.rs diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e1b7d4681ad16..933cce13549fe 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -659,12 +659,6 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "rustc_attrs", "internal rustc attributes will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_move_fragments", Normal, Gated(Stability::Unstable, - "rustc_attrs", - "the `#[rustc_move_fragments]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), ("rustc_mir", Whitelisted, Gated(Stability::Unstable, "rustc_attrs", "the `#[rustc_mir]` attribute \ diff --git a/src/test/compile-fail/feature-gate-rustc-attrs.rs b/src/test/compile-fail/feature-gate-rustc-attrs.rs index bb5b70829a163..8cfd3e020c69a 100644 --- a/src/test/compile-fail/feature-gate-rustc-attrs.rs +++ b/src/test/compile-fail/feature-gate-rustc-attrs.rs @@ -14,7 +14,6 @@ #[rustc_variance] //~ ERROR the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable #[rustc_error] //~ ERROR the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable -#[rustc_move_fragments] //~ ERROR the `#[rustc_move_fragments]` attribute is just used for rustc unit tests and will never be stable #[rustc_foo] //~^ ERROR unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics diff --git a/src/test/compile-fail/move-fragments-1.rs b/src/test/compile-fail/move-fragments-1.rs deleted file mode 100644 index 0219f5b6becb3..0000000000000 --- a/src/test/compile-fail/move-fragments-1.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2014 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. - -// Test that we correctly compute the move fragments for a fn. -// -// Note that the code below is not actually incorrect; the -// `rustc_move_fragments` attribute is a hack that uses the error -// reporting mechanisms as a channel for communicating from the -// internals of the compiler. - -// These are all fairly trivial cases: unused variables or direct -// drops of substructure. - -#![feature(rustc_attrs)] - -pub struct D { d: isize } -impl Drop for D { fn drop(&mut self) { } } - -#[rustc_move_fragments] -pub fn test_noop() { -} - -#[rustc_move_fragments] -pub fn test_take(_x: D) { - //~^ ERROR assigned_leaf_path: `$(local _x)` -} - -pub struct Pair { x: X, y: Y } - -#[rustc_move_fragments] -pub fn test_take_struct(_p: Pair) { - //~^ ERROR assigned_leaf_path: `$(local _p)` -} - -#[rustc_move_fragments] -pub fn test_drop_struct_part(p: Pair) { - //~^ ERROR parent_of_fragments: `$(local p)` - //~| ERROR moved_leaf_path: `$(local p).x` - //~| ERROR unmoved_fragment: `$(local p).y` - drop(p.x); -} - -#[rustc_move_fragments] -pub fn test_drop_tuple_part(p: (D, D)) { - //~^ ERROR parent_of_fragments: `$(local p)` - //~| ERROR moved_leaf_path: `$(local p).#0` - //~| ERROR unmoved_fragment: `$(local p).#1` - drop(p.0); -} - -pub fn main() { } diff --git a/src/test/compile-fail/move-fragments-2.rs b/src/test/compile-fail/move-fragments-2.rs deleted file mode 100644 index 15c28ec2713e9..0000000000000 --- a/src/test/compile-fail/move-fragments-2.rs +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2014-2015 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. - -// Test that we correctly compute the move fragments for a fn. -// -// Note that the code below is not actually incorrect; the -// `rustc_move_fragments` attribute is a hack that uses the error -// reporting mechanisms as a channel for communicating from the -// internals of the compiler. - -// These are checking that enums are tracked; note that their output -// paths include "downcasts" of the path to a particular enum. - -#![feature(rustc_attrs)] - -use self::Lonely::{Zero, One, Two}; - -pub struct D { d: isize } -impl Drop for D { fn drop(&mut self) { } } - -pub enum Lonely { Zero, One(X), Two(X, Y) } - -#[rustc_move_fragments] -pub fn test_match_partial(p: Lonely) { - //~^ ERROR parent_of_fragments: `$(local p)` - //~| ERROR assigned_leaf_path: `($(local p) as Lonely::Zero)` - match p { - Zero => {} - _ => {} - } -} - -#[rustc_move_fragments] -pub fn test_match_full(p: Lonely) { - //~^ ERROR parent_of_fragments: `$(local p)` - //~| ERROR assigned_leaf_path: `($(local p) as Lonely::Zero)` - //~| ERROR assigned_leaf_path: `($(local p) as Lonely::One)` - //~| ERROR assigned_leaf_path: `($(local p) as Lonely::Two)` - match p { - Zero => {} - One(..) => {} - Two(..) => {} - } -} - -#[rustc_move_fragments] -pub fn test_match_bind_one(p: Lonely) { - //~^ ERROR parent_of_fragments: `$(local p)` - //~| ERROR assigned_leaf_path: `($(local p) as Lonely::Zero)` - //~| ERROR parent_of_fragments: `($(local p) as Lonely::One)` - //~| ERROR moved_leaf_path: `($(local p) as Lonely::One).#0` - //~| ERROR assigned_leaf_path: `($(local p) as Lonely::Two)` - //~| ERROR assigned_leaf_path: `$(local data)` - match p { - Zero => {} - One(data) => {} - Two(..) => {} - } -} - -#[rustc_move_fragments] -pub fn test_match_bind_many(p: Lonely) { - //~^ ERROR parent_of_fragments: `$(local p)` - //~| ERROR assigned_leaf_path: `($(local p) as Lonely::Zero)` - //~| ERROR parent_of_fragments: `($(local p) as Lonely::One)` - //~| ERROR moved_leaf_path: `($(local p) as Lonely::One).#0` - //~| ERROR assigned_leaf_path: `$(local data)` - //~| ERROR parent_of_fragments: `($(local p) as Lonely::Two)` - //~| ERROR moved_leaf_path: `($(local p) as Lonely::Two).#0` - //~| ERROR moved_leaf_path: `($(local p) as Lonely::Two).#1` - //~| ERROR assigned_leaf_path: `$(local left)` - //~| ERROR assigned_leaf_path: `$(local right)` - match p { - Zero => {} - One(data) => {} - Two(left, right) => {} - } -} - -pub fn main() { } diff --git a/src/test/compile-fail/move-fragments-3.rs b/src/test/compile-fail/move-fragments-3.rs deleted file mode 100644 index a1152333900a0..0000000000000 --- a/src/test/compile-fail/move-fragments-3.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2014-2015 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. - -// Test that we correctly compute the move fragments for a fn. -// -// Note that the code below is not actually incorrect; the -// `rustc_move_fragments` attribute is a hack that uses the error -// reporting mechanisms as a channel for communicating from the -// internals of the compiler. - -// This checks the handling of `_` within variants, especially when mixed -// with bindings. - -#![feature(rustc_attrs)] - -use self::Lonely::{Zero, One, Two}; - -pub struct D { d: isize } -impl Drop for D { fn drop(&mut self) { } } - -pub enum Lonely { Zero, One(X), Two(X, Y) } - -#[rustc_move_fragments] -pub fn test_match_bind_and_underscore(p: Lonely) { - //~^ ERROR parent_of_fragments: `$(local p)` - //~| ERROR assigned_leaf_path: `($(local p) as Lonely::Zero)` - //~| ERROR assigned_leaf_path: `($(local p) as Lonely::One)` - //~| ERROR parent_of_fragments: `($(local p) as Lonely::Two)` - //~| ERROR moved_leaf_path: `($(local p) as Lonely::Two).#0` - //~| ERROR unmoved_fragment: `($(local p) as Lonely::Two).#1` - //~| ERROR assigned_leaf_path: `$(local left)` - - match p { - Zero => {} - - One(_) => {} // <-- does not fragment `($(local p) as One)` ... - - Two(left, _) => {} // <-- ... *does* fragment `($(local p) as Two)`. - } -} - -pub fn main() { } diff --git a/src/test/compile-fail/move-fragments-4.rs b/src/test/compile-fail/move-fragments-4.rs deleted file mode 100644 index 191e23a28638b..0000000000000 --- a/src/test/compile-fail/move-fragments-4.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2014 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. - -// Test that we correctly compute the move fragments for a fn. -// -// Note that the code below is not actually incorrect; the -// `rustc_move_fragments` attribute is a hack that uses the error -// reporting mechanisms as a channel for communicating from the -// internals of the compiler. - -// This checks that a move of deep structure is properly tracked. (An -// early draft of the code did not properly traverse up through all of -// the parents of the leaf fragment.) - -#![feature(rustc_attrs)] - -pub struct D { d: isize } -impl Drop for D { fn drop(&mut self) { } } - -pub struct Pair { x: X, y: Y } - -#[rustc_move_fragments] -pub fn test_move_substructure(pppp: Pair, D>, D>, D>) { - //~^ ERROR parent_of_fragments: `$(local pppp)` - //~| ERROR parent_of_fragments: `$(local pppp).x` - //~| ERROR parent_of_fragments: `$(local pppp).x.x` - //~| ERROR unmoved_fragment: `$(local pppp).x.x.x` - //~| ERROR moved_leaf_path: `$(local pppp).x.x.y` - //~| ERROR unmoved_fragment: `$(local pppp).x.y` - //~| ERROR unmoved_fragment: `$(local pppp).y` - drop(pppp.x.x.y); -} - -pub fn main() { } diff --git a/src/test/compile-fail/move-fragments-5.rs b/src/test/compile-fail/move-fragments-5.rs deleted file mode 100644 index 38a385eacac5c..0000000000000 --- a/src/test/compile-fail/move-fragments-5.rs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2014 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. - -// Test that we correctly compute the move fragments for a fn. -// -// Note that the code below is not actually incorrect; the -// `rustc_move_fragments` attribute is a hack that uses the error -// reporting mechanisms as a channel for communicating from the -// internals of the compiler. - -// This is the first test that checks moving into local variables. - -#![feature(rustc_attrs)] - -pub struct D { d: isize } -impl Drop for D { fn drop(&mut self) { } } - -pub struct Pair { x: X, y: Y } - -#[rustc_move_fragments] -pub fn test_move_field_to_local(p: Pair) { - //~^ ERROR parent_of_fragments: `$(local p)` - //~| ERROR moved_leaf_path: `$(local p).x` - //~| ERROR unmoved_fragment: `$(local p).y` - //~| ERROR assigned_leaf_path: `$(local _x)` - let _x = p.x; -} - -#[rustc_move_fragments] -pub fn test_move_field_to_local_to_local(p: Pair) { - //~^ ERROR parent_of_fragments: `$(local p)` - //~| ERROR moved_leaf_path: `$(local p).x` - //~| ERROR unmoved_fragment: `$(local p).y` - //~| ERROR assigned_leaf_path: `$(local _x)` - //~| ERROR moved_leaf_path: `$(local _x)` - //~| ERROR assigned_leaf_path: `$(local _y)` - let _x = p.x; - let _y = _x; -} - -// In the following fn's `test_move_field_to_local_delayed` and -// `test_uninitialized_local` , the instrumentation reports that `_x` -// is moved. This is unlike `test_move_field_to_local`, where `_x` is -// just reported as an assigned_leaf_path. Presumably because this is -// how we represent that it did not have an initializing expression at -// the binding site. - -#[rustc_move_fragments] -pub fn test_uninitialized_local(_p: Pair) { - //~^ ERROR assigned_leaf_path: `$(local _p)` - //~| ERROR moved_leaf_path: `$(local _x)` - let _x: D; -} - -#[rustc_move_fragments] -pub fn test_move_field_to_local_delayed(p: Pair) { - //~^ ERROR parent_of_fragments: `$(local p)` - //~| ERROR moved_leaf_path: `$(local p).x` - //~| ERROR unmoved_fragment: `$(local p).y` - //~| ERROR assigned_leaf_path: `$(local _x)` - //~| ERROR moved_leaf_path: `$(local _x)` - let _x; - _x = p.x; -} - -#[rustc_move_fragments] -pub fn test_move_field_mut_to_local(mut p: Pair) { - //~^ ERROR parent_of_fragments: `$(local mut p)` - //~| ERROR moved_leaf_path: `$(local mut p).x` - //~| ERROR unmoved_fragment: `$(local mut p).y` - //~| ERROR assigned_leaf_path: `$(local _x)` - let _x = p.x; -} - -#[rustc_move_fragments] -pub fn test_move_field_to_local_to_local_mut(p: Pair) { - //~^ ERROR parent_of_fragments: `$(local p)` - //~| ERROR moved_leaf_path: `$(local p).x` - //~| ERROR unmoved_fragment: `$(local p).y` - //~| ERROR assigned_leaf_path: `$(local mut _x)` - //~| ERROR moved_leaf_path: `$(local mut _x)` - //~| ERROR assigned_leaf_path: `$(local _y)` - let mut _x = p.x; - let _y = _x; -} - -pub fn main() {} diff --git a/src/test/compile-fail/move-fragments-6.rs b/src/test/compile-fail/move-fragments-6.rs deleted file mode 100644 index 122727c3f6b64..0000000000000 --- a/src/test/compile-fail/move-fragments-6.rs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2014 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. - -// Test that we correctly compute the move fragments for a fn. -// -// Note that the code below is not actually incorrect; the -// `rustc_move_fragments` attribute is a hack that uses the error -// reporting mechanisms as a channel for communicating from the -// internals of the compiler. - -// Test that moving into a field (i.e. overwriting it) fragments the -// receiver. - -#![feature(rustc_attrs)] - -use std::mem::drop; - -pub struct Pair { x: X, y: Y } - -#[rustc_move_fragments] -pub fn test_overwrite_uninit_field(z: Z) { - //~^ ERROR parent_of_fragments: `$(local mut p)` - //~| ERROR assigned_leaf_path: `$(local z)` - //~| ERROR moved_leaf_path: `$(local z)` - //~| ERROR assigned_leaf_path: `$(local mut p).x` - //~| ERROR unmoved_fragment: `$(local mut p).y` - - let mut p: Pair; - p.x = z; -} - -#[rustc_move_fragments] -pub fn test_overwrite_moved_field(mut p: Pair, z: Z) { - //~^ ERROR parent_of_fragments: `$(local mut p)` - //~| ERROR assigned_leaf_path: `$(local z)` - //~| ERROR moved_leaf_path: `$(local z)` - //~| ERROR assigned_leaf_path: `$(local mut p).y` - //~| ERROR unmoved_fragment: `$(local mut p).x` - - drop(p); - p.y = z; -} - -#[rustc_move_fragments] -pub fn test_overwrite_same_field(mut p: Pair) { - //~^ ERROR parent_of_fragments: `$(local mut p)` - //~| ERROR moved_leaf_path: `$(local mut p).x` - //~| ERROR assigned_leaf_path: `$(local mut p).x` - //~| ERROR unmoved_fragment: `$(local mut p).y` - - p.x = p.x; -} - -pub fn main() { } diff --git a/src/test/compile-fail/move-fragments-7.rs b/src/test/compile-fail/move-fragments-7.rs deleted file mode 100644 index a2a37208cd616..0000000000000 --- a/src/test/compile-fail/move-fragments-7.rs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2014 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. - -// Test that we correctly compute the move fragments for a fn. -// -// Note that the code below is not actually incorrect; the -// `rustc_move_fragments` attribute is a hack that uses the error -// reporting mechanisms as a channel for communicating from the -// internals of the compiler. - -// Test that moving a Box fragments its containing structure, for -// both moving out of the structure (i.e. reading `*p.x`) and writing -// into the container (i.e. writing `*p.x`). - -#![feature(rustc_attrs)] - -pub struct D { d: isize } -impl Drop for D { fn drop(&mut self) { } } - -pub struct Pair { x: X, y: Y } - -#[rustc_move_fragments] -pub fn test_deref_box_field(p: Pair, Box>) { - //~^ ERROR parent_of_fragments: `$(local p)` - //~| ERROR parent_of_fragments: `$(local p).x` - //~| ERROR moved_leaf_path: `$(local p).x.*` - //~| ERROR unmoved_fragment: `$(local p).y` - //~| ERROR assigned_leaf_path: `$(local i)` - let i : D = *p.x; -} - -#[rustc_move_fragments] -pub fn test_overwrite_deref_box_field(mut p: Pair, Box>) { - //~^ ERROR parent_of_fragments: `$(local mut p)` - //~| ERROR parent_of_fragments: `$(local mut p).x` - //~| ERROR assigned_leaf_path: `$(local mut p).x.*` - //~| ERROR unmoved_fragment: `$(local mut p).y` - *p.x = D { d: 3 }; -} - -pub fn main() { } diff --git a/src/test/compile-fail/move-fragments-8.rs b/src/test/compile-fail/move-fragments-8.rs deleted file mode 100644 index e57268dbfa32a..0000000000000 --- a/src/test/compile-fail/move-fragments-8.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2014 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. - -// Test that we correctly compute the move fragments for a fn. -// -// Note that the code below is not actually incorrect; the -// `rustc_move_fragments` attribute is a hack that uses the error -// reporting mechanisms as a channel for communicating from the -// internals of the compiler. - -// Test that assigning into a `&T` within structured container does -// *not* fragment its containing structure. -// -// Compare against the `Box` handling in move-fragments-7.rs. Note -// also that in this case we cannot do a move out of `&T`, so we only -// test writing `*p.x` here. - -#![feature(rustc_attrs)] - -pub struct D { d: isize } -impl Drop for D { fn drop(&mut self) { } } - -pub struct Pair { x: X, y: Y } - -#[rustc_move_fragments] -pub fn test_overwrite_deref_ampersand_field<'a>(p: Pair<&'a mut D, &'a D>) { - //~^ ERROR parent_of_fragments: `$(local p)` - //~| ERROR parent_of_fragments: `$(local p).x` - //~| ERROR assigned_leaf_path: `$(local p).x.*` - //~| ERROR unmoved_fragment: `$(local p).y` - *p.x = D { d: 3 }; -} - -pub fn main() { } diff --git a/src/test/compile-fail/move-fragments-9.rs b/src/test/compile-fail/move-fragments-9.rs deleted file mode 100644 index 350f416903400..0000000000000 --- a/src/test/compile-fail/move-fragments-9.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2014 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. - -// Test moving array structures, e.g. `[T; 3]` as well as moving -// elements in and out of such arrays. -// -// Note also that the `test_move_array_then_overwrite` tests represent -// cases that we probably should make illegal. - -#![feature(rustc_attrs)] - -pub struct D { d: isize } -impl Drop for D { fn drop(&mut self) { } } - -#[rustc_move_fragments] -pub fn test_move_array_via_return(a: [D; 3]) -> [D; 3] { - //~^ ERROR assigned_leaf_path: `$(local a)` - //~| ERROR moved_leaf_path: `$(local a)` - return a; -} - -#[rustc_move_fragments] -pub fn test_move_array_into_recv(a: [D; 3], recv: &mut [D; 3]) { - //~^ ERROR parent_of_fragments: `$(local recv)` - //~| ERROR assigned_leaf_path: `$(local a)` - //~| ERROR moved_leaf_path: `$(local a)` - //~| ERROR assigned_leaf_path: `$(local recv).*` - *recv = a; -} - -#[rustc_move_fragments] -pub fn test_overwrite_array_elem(mut a: [D; 3], i: usize, d: D) { - //~^ ERROR parent_of_fragments: `$(local mut a)` - //~| ERROR assigned_leaf_path: `$(local i)` - //~| ERROR assigned_leaf_path: `$(local d)` - //~| ERROR moved_leaf_path: `$(local d)` - //~| ERROR assigned_leaf_path: `$(local mut a).[]` - //~| ERROR unmoved_fragment: `$(allbutone $(local mut a).[])` - a[i] = d; -} - -pub fn main() { } From c87f6d854b6d75c3cc742bf78036d81e121a2be0 Mon Sep 17 00:00:00 2001 From: Venkata Giri Reddy Date: Thu, 25 May 2017 00:21:20 -0600 Subject: [PATCH 10/13] regression test for #39974 closes #39974 r? @Mark-Simulacrum --- src/test/compile-fail/issue-39974.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/test/compile-fail/issue-39974.rs diff --git a/src/test/compile-fail/issue-39974.rs b/src/test/compile-fail/issue-39974.rs new file mode 100644 index 0000000000000..6f6b775a2a3c6 --- /dev/null +++ b/src/test/compile-fail/issue-39974.rs @@ -0,0 +1,21 @@ +// 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. + +const LENGTH: f64 = 2; + +struct Thing { + f: [[f64; 2]; LENGTH], + //~^ ERROR mismatched types + //~| expected usize, found f64 +} + +fn main() { + let _t = Thing { f: [[0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0]] }; +} From 1a9c7b29d78459e061a4c83f78bb8d1464871fc1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 26 May 2017 07:46:41 -0700 Subject: [PATCH 11/13] Updated locked version of libgit2 This should include a fix for rust-lang/cargo#4091 with an updated version of libgit2. Closes rust-lang/cargo#4091 --- src/Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index e23bdbd9fd87f..6fadf148e70e4 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -165,7 +165,7 @@ dependencies = [ "hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libgit2-sys 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -472,7 +472,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libgit2-sys 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-sys 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -600,7 +600,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libgit2-sys" -version = "0.6.10" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cmake 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2056,7 +2056,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum languageserver-types 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97c2985bfcbbcb0189cfa25e1c10c1ac7111df2b6214b652c690127aefdf4e5b" "checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" "checksum libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)" = "babb8281da88cba992fa1f4ddec7d63ed96280a1a53ec9b919fd37b53d71e502" -"checksum libgit2-sys 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "dd89dd7196d5fa35b659c3eaf3c1b14b9bd961bfd1a07dfca49adeb8a6aa3763" +"checksum libgit2-sys 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d9dc31ee90fb179b706d35fb672e91d0b74e950d7fb4ea7eae3c0f5ecbf2d3d3" "checksum libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0db4ec23611747ef772db1c4d650f8bd762f07b461727ec998f953c614024b75" "checksum libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e5ee912a45d686d393d5ac87fac15ba0ba18daae14e8e7543c63ebf7fb7e970c" "checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad" From 9d018400eda8add2da8b0e1bd0e28bbc42d73426 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 26 May 2017 16:36:40 -0400 Subject: [PATCH 12/13] extend `struct_tail` to operate over closures --- src/librustc/ty/util.rs | 30 +++++++++++++++++++++++------- src/test/run-pass/issue-42210.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 src/test/run-pass/issue-42210.rs diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 01fed11fc97af..eb7744e1213e7 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -266,13 +266,29 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// if not a structure at all. Corresponds to the only possible unsized /// field, and its type can be used to determine unsizing strategy. pub fn struct_tail(self, mut ty: Ty<'tcx>) -> Ty<'tcx> { - while let TyAdt(def, substs) = ty.sty { - if !def.is_struct() { - break; - } - match def.struct_variant().fields.last() { - Some(f) => ty = f.ty(self, substs), - None => break, + loop { + match ty.sty { + ty::TyAdt(def, substs) => { + if !def.is_struct() { + break; + } + match def.struct_variant().fields.last() { + Some(f) => ty = f.ty(self, substs), + None => break, + } + } + + ty::TyTuple(tys, _) => { + if let Some((&last_ty, _)) = tys.split_last() { + ty = last_ty; + } else { + break; + } + } + + _ => { + break; + } } } ty diff --git a/src/test/run-pass/issue-42210.rs b/src/test/run-pass/issue-42210.rs new file mode 100644 index 0000000000000..ecdf78cd5bdf8 --- /dev/null +++ b/src/test/run-pass/issue-42210.rs @@ -0,0 +1,29 @@ +// Copyright 2014 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. + +// Regression test for #42210. + +// compile-flags: -g + +trait Foo { + fn foo() { } +} + +struct Bar; + +trait Baz { +} + +impl Foo for (Bar, Baz) { } + + +fn main() { + <(Bar, Baz) as Foo>::foo() +} From bf87e17cd67805e3d1e5f422c4e8fa2b0e9a3ae7 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Fri, 26 May 2017 10:54:56 -0600 Subject: [PATCH 13/13] Allow variadic functions with cdecl calling convention. --- src/librustc_typeck/diagnostics.rs | 2 +- src/librustc_typeck/lib.rs | 7 +++---- src/test/compile-fail/E0045.rs | 2 +- src/test/compile-fail/variadic-ffi-2.rs | 6 ++++-- src/test/compile-fail/variadic-ffi.rs | 6 ++++-- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index f9ebe3fff5beb..18f33dc22e743 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4078,7 +4078,7 @@ register_diagnostics! { // E0217, // ambiguous associated type, defined in multiple supertraits // E0218, // no associated type defined // E0219, // associated type defined in higher-ranked supertrait -// E0222, // Error code E0045 (variadic function must have C calling +// E0222, // Error code E0045 (variadic function must have C or cdecl calling // convention) duplicate E0224, // at least one non-builtin train is required for an object type E0227, // ambiguous lifetime bound, explicit lifetime bound required diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 6f2c73b892567..699b5f330d457 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -141,11 +141,10 @@ fn require_c_abi_if_variadic(tcx: TyCtxt, decl: &hir::FnDecl, abi: Abi, span: Span) { - if decl.variadic && abi != Abi::C { + if decl.variadic && !(abi == Abi::C || abi == Abi::Cdecl) { let mut err = struct_span_err!(tcx.sess, span, E0045, - "variadic function must have C calling convention"); - err.span_label(span, "variadics require C calling conventions") - .emit(); + "variadic function must have C or cdecl calling convention"); + err.span_label(span, "variadics require C or cdecl calling convention").emit(); } } diff --git a/src/test/compile-fail/E0045.rs b/src/test/compile-fail/E0045.rs index a3fea8e0db299..3f098861eb60c 100644 --- a/src/test/compile-fail/E0045.rs +++ b/src/test/compile-fail/E0045.rs @@ -9,7 +9,7 @@ // except according to those terms. extern "Rust" { fn foo(x: u8, ...); } //~ ERROR E0045 - //~| NOTE variadics require C calling conventions + //~| NOTE variadics require C or cdecl calling convention fn main() { } diff --git a/src/test/compile-fail/variadic-ffi-2.rs b/src/test/compile-fail/variadic-ffi-2.rs index afcad9d8f9614..ec5669f639277 100644 --- a/src/test/compile-fail/variadic-ffi-2.rs +++ b/src/test/compile-fail/variadic-ffi-2.rs @@ -8,8 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn baz(f: extern "cdecl" fn(usize, ...)) { - //~^ ERROR: variadic function must have C calling convention +// ignore-arm stdcall isn't suppported + +fn baz(f: extern "stdcall" fn(usize, ...)) { + //~^ ERROR: variadic function must have C or cdecl calling convention f(22, 44); } diff --git a/src/test/compile-fail/variadic-ffi.rs b/src/test/compile-fail/variadic-ffi.rs index af2b552e20f14..125177efc53c7 100644 --- a/src/test/compile-fail/variadic-ffi.rs +++ b/src/test/compile-fail/variadic-ffi.rs @@ -8,8 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern "cdecl" { - fn printf(_: *const u8, ...); //~ ERROR: variadic function must have C calling convention +// ignore-arm stdcall isn't suppported + +extern "stdcall" { + fn printf(_: *const u8, ...); //~ ERROR: variadic function must have C or cdecl calling } extern {