From a47fd3df89c267829d96748b3bdff305f20d27d5 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Tue, 20 Feb 2018 13:49:54 -0500
Subject: [PATCH 01/14] make `#[unwind]` attribute specify expectations more
 clearly

You can now choose between the following:

- `#[unwind(allowed)]`
- `#[unwind(aborts)]`

Per rust-lang/rust#48251, the default is `#[unwind(allowed)]`, though
I think we should change this eventually.
---
 src/libcore/panicking.rs             |  3 +-
 src/libpanic_unwind/gcc.rs           |  3 +-
 src/libpanic_unwind/lib.rs           |  3 +-
 src/libpanic_unwind/seh64_gnu.rs     |  3 +-
 src/libpanic_unwind/windows.rs       |  9 ++++--
 src/librustc_mir/build/mod.rs        | 19 ++++++++----
 src/libstd/panicking.rs              |  6 ++--
 src/libsyntax/attr.rs                | 45 ++++++++++++++++++++++++++++
 src/libsyntax/diagnostic_list.rs     | 27 +++++++++++++++++
 src/libsyntax/feature_gate.rs        |  2 +-
 src/libunwind/libunwind.rs           |  9 ++++--
 src/test/codegen/extern-functions.rs |  2 +-
 src/test/run-pass/abort-on-c-abi.rs  |  1 +
 13 files changed, 113 insertions(+), 19 deletions(-)

diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs
index 4170d91e5fce2..94db0baa3f95f 100644
--- a/src/libcore/panicking.rs
+++ b/src/libcore/panicking.rs
@@ -64,7 +64,8 @@ pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32))
     #[allow(improper_ctypes)]
     extern {
         #[lang = "panic_fmt"]
-        #[unwind]
+        #[cfg_attr(stage0, unwind)]
+        #[cfg_attr(not(stage0), unwind(allowed))]
         fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: u32, col: u32) -> !;
     }
     let (file, line, col) = *file_line_col;
diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs
index 63e44f71a3a8f..ca2fd561cadcf 100644
--- a/src/libpanic_unwind/gcc.rs
+++ b/src/libpanic_unwind/gcc.rs
@@ -286,7 +286,8 @@ unsafe fn find_eh_action(context: *mut uw::_Unwind_Context)
 // See docs in the `unwind` module.
 #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
 #[lang = "eh_unwind_resume"]
-#[unwind]
+#[cfg_attr(stage0, unwind)]
+#[cfg_attr(not(stage0), unwind(allowed))]
 unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: *mut u8) -> ! {
     uw::_Unwind_Resume(panic_ctx as *mut uw::_Unwind_Exception);
 }
diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs
index 92e40e8f26d40..a5cebc3e4d04b 100644
--- a/src/libpanic_unwind/lib.rs
+++ b/src/libpanic_unwind/lib.rs
@@ -112,7 +112,8 @@ pub unsafe extern "C" fn __rust_maybe_catch_panic(f: fn(*mut u8),
 // Entry point for raising an exception, just delegates to the platform-specific
 // implementation.
 #[no_mangle]
-#[unwind]
+#[cfg_attr(stage0, unwind)]
+#[cfg_attr(not(stage0), unwind(allowed))]
 pub unsafe extern "C" fn __rust_start_panic(data: usize, vtable: usize) -> u32 {
     imp::panic(mem::transmute(raw::TraitObject {
         data: data as *mut (),
diff --git a/src/libpanic_unwind/seh64_gnu.rs b/src/libpanic_unwind/seh64_gnu.rs
index 0a9fa7d9a80b4..090cd095380ee 100644
--- a/src/libpanic_unwind/seh64_gnu.rs
+++ b/src/libpanic_unwind/seh64_gnu.rs
@@ -108,7 +108,8 @@ unsafe extern "C" fn rust_eh_personality(exceptionRecord: *mut c::EXCEPTION_RECO
 }
 
 #[lang = "eh_unwind_resume"]
-#[unwind]
+#[cfg_attr(stage0, unwind)]
+#[cfg_attr(not(stage0), unwind(allowed))]
 unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! {
     let params = [panic_ctx as c::ULONG_PTR];
     c::RaiseException(RUST_PANIC,
diff --git a/src/libpanic_unwind/windows.rs b/src/libpanic_unwind/windows.rs
index a7e90071ceae8..50fba5faee747 100644
--- a/src/libpanic_unwind/windows.rs
+++ b/src/libpanic_unwind/windows.rs
@@ -79,18 +79,21 @@ pub enum EXCEPTION_DISPOSITION {
 pub use self::EXCEPTION_DISPOSITION::*;
 
 extern "system" {
-    #[unwind]
+    #[cfg_attr(stage0, unwind)]
+    #[cfg_attr(not(stage0), unwind(allowed))]
     pub fn RaiseException(dwExceptionCode: DWORD,
                           dwExceptionFlags: DWORD,
                           nNumberOfArguments: DWORD,
                           lpArguments: *const ULONG_PTR);
-    #[unwind]
+    #[cfg_attr(stage0, unwind)]
+    #[cfg_attr(not(stage0), unwind(allowed))]
     pub fn RtlUnwindEx(TargetFrame: LPVOID,
                        TargetIp: LPVOID,
                        ExceptionRecord: *const EXCEPTION_RECORD,
                        ReturnValue: LPVOID,
                        OriginalContext: *const CONTEXT,
                        HistoryTable: *const UNWIND_HISTORY_TABLE);
-    #[unwind]
+    #[cfg_attr(stage0, unwind)]
+    #[cfg_attr(not(stage0), unwind(allowed))]
     pub fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8);
 }
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 57059cd31a1bc..a325cfe3eaae3 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -28,6 +28,7 @@ use std::mem;
 use std::u32;
 use syntax::abi::Abi;
 use syntax::ast;
+use syntax::attr::{self, UnwindAttr};
 use syntax::symbol::keywords;
 use syntax_pos::Span;
 use transform::MirSource;
@@ -355,10 +356,9 @@ macro_rules! unpack {
 }
 
 fn should_abort_on_panic<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                         fn_id: ast::NodeId,
+                                         fn_def_id: DefId,
                                          abi: Abi)
                                          -> bool {
-
     // Not callable from C, so we can safely unwind through these
     if abi == Abi::Rust || abi == Abi::RustCall { return false; }
 
@@ -370,9 +370,17 @@ fn should_abort_on_panic<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
 
     // This is a special case: some functions have a C abi but are meant to
     // unwind anyway. Don't stop them.
-    if tcx.has_attr(tcx.hir.local_def_id(fn_id), "unwind") { return false; }
+    let attrs = &tcx.get_attrs(fn_def_id);
+    match attr::find_unwind_attr(Some(tcx.sess.diagnostic()), attrs) {
+        None => {
+            // FIXME(rust-lang/rust#48251) -- Had to disable
+            // abort-on-panic for backwards compatibility reasons.
+            false
+        }
 
-    return true;
+        Some(UnwindAttr::Allowed) => false,
+        Some(UnwindAttr::Aborts) => true,
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -399,13 +407,14 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
         safety,
         return_ty);
 
+    let fn_def_id = tcx.hir.local_def_id(fn_id);
     let call_site_scope = region::Scope::CallSite(body.value.hir_id.local_id);
     let arg_scope = region::Scope::Arguments(body.value.hir_id.local_id);
     let mut block = START_BLOCK;
     let source_info = builder.source_info(span);
     let call_site_s = (call_site_scope, source_info);
     unpack!(block = builder.in_scope(call_site_s, LintLevel::Inherited, block, |builder| {
-        if should_abort_on_panic(tcx, fn_id, abi) {
+        if should_abort_on_panic(tcx, fn_def_id, abi) {
             builder.schedule_abort();
         }
 
diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs
index 161c3fc7113a7..454ac64735c67 100644
--- a/src/libstd/panicking.rs
+++ b/src/libstd/panicking.rs
@@ -55,7 +55,8 @@ extern {
                                 data: *mut u8,
                                 data_ptr: *mut usize,
                                 vtable_ptr: *mut usize) -> u32;
-    #[unwind]
+    #[cfg_attr(stage0, unwind)]
+    #[cfg_attr(not(stage0), unwind(allowed))]
     fn __rust_start_panic(data: usize, vtable: usize) -> u32;
 }
 
@@ -315,7 +316,8 @@ pub fn panicking() -> bool {
 /// Entry point of panic from the libcore crate.
 #[cfg(not(test))]
 #[lang = "panic_fmt"]
-#[unwind]
+#[cfg_attr(stage0, unwind)]
+#[cfg_attr(not(stage0), unwind(allowed))]
 pub extern fn rust_begin_panic(msg: fmt::Arguments,
                                file: &'static str,
                                line: u32,
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index d18d6f5e6bd0d..d0822b69aa692 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -565,6 +565,51 @@ pub fn find_inline_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> In
     })
 }
 
+#[derive(Copy, Clone, PartialEq)]
+pub enum UnwindAttr {
+    Allowed,
+    Aborts,
+}
+
+/// Determine what `#[unwind]` attribute is present in `attrs`, if any.
+pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Option<UnwindAttr> {
+    let syntax_error = |attr: &Attribute| {
+        mark_used(attr);
+        diagnostic.map(|d| {
+            span_err!(d, attr.span, E0633, "malformed `#[unwind]` attribute");
+        });
+        None
+    };
+
+    attrs.iter().fold(None, |ia, attr| {
+        if attr.path != "unwind" {
+            return ia;
+        }
+        let meta = match attr.meta() {
+            Some(meta) => meta.node,
+            None => return ia,
+        };
+        match meta {
+            MetaItemKind::Word => {
+                syntax_error(attr)
+            }
+            MetaItemKind::List(ref items) => {
+                mark_used(attr);
+                if items.len() != 1 {
+                    syntax_error(attr)
+                } else if list_contains_name(&items[..], "allowed") {
+                    Some(UnwindAttr::Allowed)
+                } else if list_contains_name(&items[..], "aborts") {
+                    Some(UnwindAttr::Aborts)
+                } else {
+                    syntax_error(attr)
+                }
+            }
+            _ => ia,
+        }
+    })
+}
+
 /// True if `#[inline]` or `#[inline(always)]` is present in `attrs`.
 pub fn requests_inline(attrs: &[Attribute]) -> bool {
     match find_inline_attr(None, attrs) {
diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs
index d841281e48580..84ab0336f1671 100644
--- a/src/libsyntax/diagnostic_list.rs
+++ b/src/libsyntax/diagnostic_list.rs
@@ -342,6 +342,33 @@ fn main() {
 ```
 "##,
 
+E0633: r##"
+The `unwind` attribute was malformed.
+
+Erroneous code example:
+
+```ignore (compile_fail not working here; see Issue #43707)
+#[unwind()] // error: expected one argument
+pub extern fn something() {}
+
+fn main() {}
+```
+
+The `#[unwind]` attribute should be used as follows:
+
+- `#[unwind(aborts)]` -- specifies that if a non-Rust ABI function
+  should abort the process if it attempts to unwind. This is the safer
+  and preferred option.
+
+- `#[unwind(allowed)]` -- specifies that a non-Rust ABI function
+  should be allowed to unwind. This can easily result in Undefined
+  Behavior (UB), so be careful.
+
+NB. The default behavior here is "allowed", but this is unspecified
+and likely to change in the future.
+
+"##,
+
 }
 
 register_diagnostics! {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 3b137f9570a39..f1d0a70a22cd0 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -233,7 +233,7 @@ declare_features! (
     // allow `extern "platform-intrinsic" { ... }`
     (active, platform_intrinsics, "1.4.0", Some(27731)),
 
-    // allow `#[unwind]`
+    // allow `#[unwind(..)]`
     // rust runtime internal
     (active, unwind_attributes, "1.4.0", None),
 
diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs
index e6fff7963f79c..aa73b11fb3813 100644
--- a/src/libunwind/libunwind.rs
+++ b/src/libunwind/libunwind.rs
@@ -83,7 +83,8 @@ pub enum _Unwind_Context {}
 pub type _Unwind_Exception_Cleanup_Fn = extern "C" fn(unwind_code: _Unwind_Reason_Code,
                                                       exception: *mut _Unwind_Exception);
 extern "C" {
-    #[unwind]
+    #[cfg_attr(stage0, unwind)]
+    #[cfg_attr(not(stage0), unwind(allowed))]
     pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
     pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
     pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void;
@@ -220,7 +221,8 @@ if #[cfg(all(any(target_os = "ios", not(target_arch = "arm"))))] {
 if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] {
     // Not 32-bit iOS
     extern "C" {
-        #[unwind]
+        #[cfg_attr(stage0, unwind)]
+        #[cfg_attr(not(stage0), unwind(allowed))]
         pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
         pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
                                  trace_argument: *mut c_void)
@@ -229,7 +231,8 @@ if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] {
 } else {
     // 32-bit iOS uses SjLj and does not provide _Unwind_Backtrace()
     extern "C" {
-        #[unwind]
+        #[cfg_attr(stage0, unwind)]
+        #[cfg_attr(not(stage0), unwind(allowed))]
         pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
     }
 
diff --git a/src/test/codegen/extern-functions.rs b/src/test/codegen/extern-functions.rs
index 7ee31070b2635..90ee0c75680dc 100644
--- a/src/test/codegen/extern-functions.rs
+++ b/src/test/codegen/extern-functions.rs
@@ -19,7 +19,7 @@ extern {
     fn extern_fn();
 // CHECK-NOT: Function Attrs: nounwind
 // CHECK: declare void @unwinding_extern_fn
-    #[unwind]
+    #[unwind(allowed)]
     fn unwinding_extern_fn();
 }
 
diff --git a/src/test/run-pass/abort-on-c-abi.rs b/src/test/run-pass/abort-on-c-abi.rs
index 17661c0b12097..5039c334f26f5 100644
--- a/src/test/run-pass/abort-on-c-abi.rs
+++ b/src/test/run-pass/abort-on-c-abi.rs
@@ -19,6 +19,7 @@ use std::io::prelude::*;
 use std::io;
 use std::process::{Command, Stdio};
 
+#[unwind(aborts)]
 extern "C" fn panic_in_ffi() {
     panic!("Test");
 }

From 566c6ac6bac479d4977339fc91bb497cb96342c6 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Wed, 21 Feb 2018 20:39:01 -0500
Subject: [PATCH 02/14] add `unwind_attributes` feature

---
 src/test/run-pass/abort-on-c-abi.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/test/run-pass/abort-on-c-abi.rs b/src/test/run-pass/abort-on-c-abi.rs
index 5039c334f26f5..ef368ed604bea 100644
--- a/src/test/run-pass/abort-on-c-abi.rs
+++ b/src/test/run-pass/abort-on-c-abi.rs
@@ -14,6 +14,8 @@
 // ignore-cloudabi no env and process
 // ignore-emscripten no processes
 
+#![feature(unwind_attributes)]
+
 use std::{env, panic};
 use std::io::prelude::*;
 use std::io;

From 56a68285332000c858e9aeba7d66a4ec66ebff91 Mon Sep 17 00:00:00 2001
From: Jeremy Fitzhardinge <jeremy@goop.org>
Date: Sun, 18 Feb 2018 15:05:24 -0800
Subject: [PATCH 03/14] Implement --remap-path-prefix

Remove experimental -Zremap-path-prefix-from/to, and replace it with
the stabilized --remap-path-prefix=from=to variant.

This is an implementation for issue of #41555.
---
 src/doc/man/rustc.1                           | 10 ++++
 .../src/compiler-flags/remap-path-prefix.md   | 37 ---------------
 src/libproc_macro/lib.rs                      |  2 +-
 src/librustc/session/config.rs                | 47 +++++++++----------
 src/librustc_metadata/encoder.rs              |  2 +-
 src/libsyntax/codemap.rs                      |  2 +-
 src/libsyntax_pos/lib.rs                      |  2 +-
 .../auxiliary/remap_path_prefix_aux.rs        |  2 +-
 src/test/codegen/remap_path_prefix/main.rs    |  2 +-
 .../auxiliary/extern_crate.rs                 |  2 +-
 10 files changed, 38 insertions(+), 70 deletions(-)
 delete mode 100644 src/doc/unstable-book/src/compiler-flags/remap-path-prefix.md

diff --git a/src/doc/man/rustc.1 b/src/doc/man/rustc.1
index 19f6cc9ac619d..39d1053995945 100644
--- a/src/doc/man/rustc.1
+++ b/src/doc/man/rustc.1
@@ -125,6 +125,16 @@ Print version info and exit.
 \fB\-v\fR, \fB\-\-verbose\fR
 Use verbose output.
 .TP
+\fB\-\-remap\-path\-prefix\fR \fIfrom\fR=\fIto\fR
+Remap source path prefixes in all output, including compiler diagnostics, debug information,
+macro expansions, etc. The \fIfrom\fR=\fIto\fR parameter is scanned from right to left, so \fIfrom\fR
+may contain '=', but \fIto\fR may not.
+
+This is useful for normalizing build products, for example by removing the current directory out of
+pathnames emitted into the object files. The replacement is purely textual, with no consideration of
+the current system's pathname syntax. For example \fI\-\-remap\-path\-prefix foo=bar\fR will
+match \fBfoo/lib.rs\fR but not \fB./foo/lib.rs\fR.
+.TP
 \fB\-\-extern\fR \fINAME\fR=\fIPATH\fR
 Specify where an external rust library is located. These should match
 \fIextern\fR declarations in the crate's source code.
diff --git a/src/doc/unstable-book/src/compiler-flags/remap-path-prefix.md b/src/doc/unstable-book/src/compiler-flags/remap-path-prefix.md
deleted file mode 100644
index 8ca04d2532592..0000000000000
--- a/src/doc/unstable-book/src/compiler-flags/remap-path-prefix.md
+++ /dev/null
@@ -1,37 +0,0 @@
-# `remap-path-prefix`
-
-The tracking issue for this feature is: [#41555](https://github.com/rust-lang/rust/issues/41555)
-
-------------------------
-
-The `-Z remap-path-prefix-from`, `-Z remap-path-prefix-to` commandline option
-pair allows to replace prefixes of any file paths the compiler emits in various
-places. This is useful for bringing debuginfo paths into a well-known form and
-for achieving reproducible builds independent of the directory the compiler was
-executed in. All paths emitted by the compiler are affected, including those in
-error messages.
-
-In order to map all paths starting with `/home/foo/my-project/src` to
-`/sources/my-project`, one would invoke the compiler as follows:
-
-```text
-rustc -Zremap-path-prefix-from="/home/foo/my-project/src" -Zremap-path-prefix-to="/sources/my-project"
-```
-
-Debuginfo for code from the file `/home/foo/my-project/src/foo/mod.rs`,
-for example, would then point debuggers to `/sources/my-project/foo/mod.rs`
-instead of the original file.
-
-The options can be specified multiple times when multiple prefixes should be
-mapped:
-
-```text
-rustc -Zremap-path-prefix-from="/home/foo/my-project/src" \
-      -Zremap-path-prefix-to="/sources/my-project" \
-      -Zremap-path-prefix-from="/home/foo/my-project/build-dir" \
-      -Zremap-path-prefix-to="/stable-build-dir"
-```
-
-When the options are given multiple times, the nth `-from` will be matched up
-with the nth `-to` and they can appear anywhere on the commandline. Mappings
-specified later on the line will take precedence over earlier ones.
diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index 6768e0ade4304..0f31ac15a4545 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -316,7 +316,7 @@ impl SourceFile {
     /// If the code span associated with this `SourceFile` was generated by an external macro, this
     /// may not be an actual path on the filesystem. Use [`is_real`] to check.
     ///
-    /// Also note that even if `is_real` returns `true`, if `-Z remap-path-prefix-*` was passed on
+    /// Also note that even if `is_real` returns `true`, if `--remap-path-prefix` was passed on
     /// the command line, the path as given may not actually be valid.
     ///
     /// [`is_real`]: #method.is_real
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index cfbf233297cf8..1d554cb0d821d 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -435,6 +435,9 @@ top_level_options!(
         // if we otherwise use the defaults of rustc.
         cli_forced_codegen_units: Option<usize> [UNTRACKED],
         cli_forced_thinlto_off: bool [UNTRACKED],
+
+        // Remap source path prefixes in all output (messages, object files, debug, etc)
+        remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
     }
 );
 
@@ -617,6 +620,7 @@ pub fn basic_options() -> Options {
         actually_rustdoc: false,
         cli_forced_codegen_units: None,
         cli_forced_thinlto_off: false,
+        remap_path_prefix: Vec::new(),
     }
 }
 
@@ -635,11 +639,7 @@ impl Options {
     }
 
     pub fn file_path_mapping(&self) -> FilePathMapping {
-        FilePathMapping::new(
-            self.debugging_opts.remap_path_prefix_from.iter().zip(
-                self.debugging_opts.remap_path_prefix_to.iter()
-            ).map(|(src, dst)| (src.clone(), dst.clone())).collect()
-        )
+        FilePathMapping::new(self.remap_path_prefix.clone())
     }
 
     /// True if there will be an output file generated
@@ -1269,10 +1269,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "set the optimization fuel quota for a crate"),
     print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
         "make Rustc print the total optimization fuel used by a crate"),
-    remap_path_prefix_from: Vec<PathBuf> = (vec![], parse_pathbuf_push, [UNTRACKED],
-        "add a source pattern to the file path remapping config"),
-    remap_path_prefix_to: Vec<PathBuf> = (vec![], parse_pathbuf_push, [UNTRACKED],
-        "add a mapping target to the file path remapping config"),
     force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
         "force all crates to be `rustc_private` unstable"),
     pre_link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
@@ -1595,6 +1591,7 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
                   `expanded` (crates expanded), or
                   `expanded,identified` (fully parenthesized, AST nodes with IDs).",
                  "TYPE"),
+        opt::multi_s("", "remap-path-prefix", "remap source names in output", "FROM=TO"),
     ]);
     opts
 }
@@ -1718,23 +1715,6 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
         output_types.insert(OutputType::Exe, None);
     }
 
-    let remap_path_prefix_sources = debugging_opts.remap_path_prefix_from.len();
-    let remap_path_prefix_targets = debugging_opts.remap_path_prefix_to.len();
-
-    if remap_path_prefix_targets < remap_path_prefix_sources {
-        for source in &debugging_opts.remap_path_prefix_from[remap_path_prefix_targets..] {
-            early_error(error_format,
-                &format!("option `-Zremap-path-prefix-from='{}'` does not have \
-                         a corresponding `-Zremap-path-prefix-to`", source.display()))
-        }
-    } else if remap_path_prefix_targets > remap_path_prefix_sources {
-        for target in &debugging_opts.remap_path_prefix_to[remap_path_prefix_sources..] {
-            early_error(error_format,
-                &format!("option `-Zremap-path-prefix-to='{}'` does not have \
-                          a corresponding `-Zremap-path-prefix-from`", target.display()))
-        }
-    }
-
     let mut cg = build_codegen_options(matches, error_format);
     let mut codegen_units = cg.codegen_units;
     let mut disable_thinlto = false;
@@ -1968,6 +1948,20 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
 
     let crate_name = matches.opt_str("crate-name");
 
+    let remap_path_prefix = matches.opt_strs("remap-path-prefix")
+        .into_iter()
+        .map(|remap| {
+            let mut parts = remap.rsplitn(2, '='); // reverse iterator
+            let to = parts.next();
+            let from = parts.next();
+            match (from, to) {
+                (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
+                _ => early_error(error_format,
+                        "--remap-path-prefix must contain '=' between FROM and TO"),
+            }
+        })
+        .collect();
+
     (Options {
         crate_types,
         optimize: opt_level,
@@ -1995,6 +1989,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
         actually_rustdoc: false,
         cli_forced_codegen_units: codegen_units,
         cli_forced_thinlto_off: disable_thinlto,
+        remap_path_prefix,
     },
     cfg)
 }
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 78578ca179c82..d140b135416c9 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -323,7 +323,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 // paths because any relative paths are potentially relative to
                 // a wrong directory.
                 // However, if a path has been modified via
-                // `-Zremap-path-prefix` we assume the user has already set
+                // `--remap-path-prefix` we assume the user has already set
                 // things up the way they want and don't touch the path values
                 // anymore.
                 match filemap.name {
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index df5845f6c217d..926548b60318b 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -129,7 +129,7 @@ pub struct CodeMap {
     pub(super) files: RefCell<Vec<Rc<FileMap>>>,
     file_loader: Box<FileLoader>,
     // This is used to apply the file path remapping as specified via
-    // -Zremap-path-prefix to all FileMaps allocated within this CodeMap.
+    // --remap-path-prefix to all FileMaps allocated within this CodeMap.
     path_mapping: FilePathMapping,
     stable_id_to_filemap: RefCell<FxHashMap<StableFilemapId, Rc<FileMap>>>,
     /// In case we are in a doctest, replace all file names with the PathBuf,
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index 294506625bc05..e3f1417456c8a 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -664,7 +664,7 @@ pub struct FileMap {
     /// originate from files has names between angle brackets by convention,
     /// e.g. `<anon>`
     pub name: FileName,
-    /// True if the `name` field above has been modified by -Zremap-path-prefix
+    /// True if the `name` field above has been modified by --remap-path-prefix
     pub name_was_remapped: bool,
     /// The unmapped path of the file that the source came from.
     /// Set to `None` if the FileMap was imported from an external crate.
diff --git a/src/test/codegen/remap_path_prefix/auxiliary/remap_path_prefix_aux.rs b/src/test/codegen/remap_path_prefix/auxiliary/remap_path_prefix_aux.rs
index 5543a091680f1..3ef0ff9ef0687 100644
--- a/src/test/codegen/remap_path_prefix/auxiliary/remap_path_prefix_aux.rs
+++ b/src/test/codegen/remap_path_prefix/auxiliary/remap_path_prefix_aux.rs
@@ -10,7 +10,7 @@
 
 // ignore-tidy-linelength
 
-// compile-flags: -g  -Zremap-path-prefix-from={{cwd}} -Zremap-path-prefix-to=/the/aux-cwd -Zremap-path-prefix-from={{src-base}}/remap_path_prefix/auxiliary -Zremap-path-prefix-to=/the/aux-src
+// compile-flags: -g  --remap-path-prefix={{cwd}}=/the/aux-cwd --remap-path-prefix={{src-base}}/remap_path_prefix/auxiliary=/the/aux-src
 
 #[inline]
 pub fn some_aux_function() -> i32 {
diff --git a/src/test/codegen/remap_path_prefix/main.rs b/src/test/codegen/remap_path_prefix/main.rs
index ea0c9ad2b8324..2f46b6c5d48da 100644
--- a/src/test/codegen/remap_path_prefix/main.rs
+++ b/src/test/codegen/remap_path_prefix/main.rs
@@ -11,7 +11,7 @@
 // ignore-windows
 // ignore-tidy-linelength
 
-// compile-flags: -g  -C no-prepopulate-passes -Zremap-path-prefix-from={{cwd}} -Zremap-path-prefix-to=/the/cwd -Zremap-path-prefix-from={{src-base}} -Zremap-path-prefix-to=/the/src
+// compile-flags: -g  -C no-prepopulate-passes --remap-path-prefix={{cwd}}=/the/cwd --remap-path-prefix={{src-base}}=/the/src
 // aux-build:remap_path_prefix_aux.rs
 
 extern crate remap_path_prefix_aux;
diff --git a/src/test/incremental/remapped_paths_cc/auxiliary/extern_crate.rs b/src/test/incremental/remapped_paths_cc/auxiliary/extern_crate.rs
index 1483bf92c9708..c80b334623b43 100644
--- a/src/test/incremental/remapped_paths_cc/auxiliary/extern_crate.rs
+++ b/src/test/incremental/remapped_paths_cc/auxiliary/extern_crate.rs
@@ -12,7 +12,7 @@
 
 //[rpass1] compile-flags: -g
 //[rpass2] compile-flags: -g
-//[rpass3] compile-flags: -g -Zremap-path-prefix-from={{src-base}} -Zremap-path-prefix-to=/the/src
+//[rpass3] compile-flags: -g --remap-path-prefix={{src-base}}=/the/src
 
 #![feature(rustc_attrs)]
 #![crate_type="rlib"]

From d9438c30d59bbe7c4442e4a824a41a2bd00372ac Mon Sep 17 00:00:00 2001
From: Manish Goregaokar <manishsmail@gmail.com>
Date: Thu, 22 Feb 2018 15:25:31 -0800
Subject: [PATCH 04/14] Add ToString and FromStr impls for Epoch

---
 src/librustc/session/config.rs | 38 +++++++++++++++++++++++++++++-----
 1 file changed, 33 insertions(+), 5 deletions(-)

diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index cfbf233297cf8..ef85ef8e37e70 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -41,7 +41,7 @@ use std::collections::btree_map::Iter as BTreeMapIter;
 use std::collections::btree_map::Keys as BTreeMapKeysIter;
 use std::collections::btree_map::Values as BTreeMapValuesIter;
 
-use std::fmt;
+use std::{fmt, str};
 use std::hash::Hasher;
 use std::collections::hash_map::DefaultHasher;
 use std::collections::HashSet;
@@ -137,6 +137,28 @@ pub enum Epoch {
     // as well as changing the default Cargo template.
 }
 
+pub const ALL_EPOCHS: &[Epoch] = &[Epoch::Epoch2015, Epoch::Epoch2018];
+
+impl ToString for Epoch {
+    fn to_string(&self) -> String {
+        match *self {
+            Epoch::Epoch2015 => "2015".into(),
+            Epoch::Epoch2018 => "2018".into(),
+        }
+    }
+}
+
+impl str::FromStr for Epoch {
+    type Err = ();
+    fn from_str(s: &str) -> Result<Self, ()> {
+        match s {
+            "2015" => Ok(Epoch::Epoch2015),
+            "2018" => Ok(Epoch::Epoch2018),
+            _ => Err(())
+        }
+    }
+}
+
 impl_stable_hash_for!(enum self::OutputType {
     Bitcode,
     Assembly,
@@ -1021,11 +1043,17 @@ macro_rules! options {
 
         fn parse_epoch(slot: &mut Epoch, v: Option<&str>) -> bool {
             match v {
-                Some("2015") => *slot = Epoch::Epoch2015,
-                Some("2018") => *slot = Epoch::Epoch2018,
-                _ => return false,
+                Some(s) => {
+                    let epoch = s.parse();
+                    if let Ok(parsed) = epoch {
+                        *slot = parsed;
+                        true
+                    } else {
+                        false
+                    }
+                }
+                _ => false,
             }
-            true
         }
     }
 ) }

From da9dc0507bc86104db8bf7a99e849bfd995fb1ef Mon Sep 17 00:00:00 2001
From: Manish Goregaokar <manishsmail@gmail.com>
Date: Thu, 22 Feb 2018 16:51:42 -0800
Subject: [PATCH 05/14] Allow future-incompat lints to mention an epoch

---
 src/librustc/lint/context.rs   | 27 ++++++++++++++++++++++-----
 src/librustc/lint/levels.rs    | 17 ++++++++++-------
 src/librustc/lint/mod.rs       | 29 +++++++++++++++++++++++++----
 src/librustc/session/config.rs | 11 ++++++++++-
 src/librustc/session/mod.rs    |  4 ++++
 src/librustc/ty/context.rs     |  2 +-
 src/librustc_driver/driver.rs  |  2 +-
 src/librustc_driver/lib.rs     | 20 ++++++++++----------
 src/librustc_lint/lib.rs       | 18 ++++++++++++++++++
 9 files changed, 101 insertions(+), 29 deletions(-)

diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index ed937046e5ed7..870b52c221f37 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -99,7 +99,11 @@ pub struct BufferedEarlyLint {
 /// guidelines.
 pub struct FutureIncompatibleInfo {
     pub id: LintId,
-    pub reference: &'static str // e.g., a URL for an issue/PR/RFC or error code
+    /// e.g., a URL for an issue/PR/RFC or error code
+    pub reference: &'static str,
+    /// If this is an epoch fixing lint, the epoch in which
+    /// this lint becomes obsolete
+    pub epoch: Option<config::Epoch>,
 }
 
 /// The target of the `by_name` map, which accounts for renaming/deprecation.
@@ -194,11 +198,24 @@ impl LintStore {
     pub fn register_future_incompatible(&mut self,
                                         sess: Option<&Session>,
                                         lints: Vec<FutureIncompatibleInfo>) {
-        let ids = lints.iter().map(|f| f.id).collect();
-        self.register_group(sess, false, "future_incompatible", ids);
-        for info in lints {
-            self.future_incompatible.insert(info.id, info);
+
+        for epoch in config::ALL_EPOCHS {
+            let lints = lints.iter().filter(|f| f.epoch == Some(*epoch)).map(|f| f.id)
+                             .collect::<Vec<_>>();
+            if !lints.is_empty() {
+                self.register_group(sess, false, epoch.lint_name(), lints)
+            }
+        }
+
+        let mut future_incompatible = vec![];
+        for lint in lints {
+            future_incompatible.push(lint.id);
+            self.future_incompatible.insert(lint.id, lint);
         }
+
+        self.register_group(sess, false, "future_incompatible", future_incompatible);
+
+
     }
 
     pub fn future_incompatible(&self, id: LintId) -> Option<&FutureIncompatibleInfo> {
diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs
index 4bc37747f2a76..909904b4fc36c 100644
--- a/src/librustc/lint/levels.rs
+++ b/src/librustc/lint/levels.rs
@@ -89,14 +89,15 @@ impl LintLevelSets {
     fn get_lint_level(&self,
                       lint: &'static Lint,
                       idx: u32,
-                      aux: Option<&FxHashMap<LintId, (Level, LintSource)>>)
+                      aux: Option<&FxHashMap<LintId, (Level, LintSource)>>,
+                      sess: &Session)
         -> (Level, LintSource)
     {
         let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux);
 
         // If `level` is none then we actually assume the default level for this
         // lint.
-        let mut level = level.unwrap_or(lint.default_level);
+        let mut level = level.unwrap_or(lint.default_level(sess));
 
         // If we're about to issue a warning, check at the last minute for any
         // directives against the warnings "lint". If, for example, there's an
@@ -235,7 +236,8 @@ impl<'a> LintLevelsBuilder<'a> {
                         let lint = builtin::RENAMED_AND_REMOVED_LINTS;
                         let (level, src) = self.sets.get_lint_level(lint,
                                                                     self.cur,
-                                                                    Some(&specs));
+                                                                    Some(&specs),
+                                                                    &sess);
                         lint::struct_lint_level(self.sess,
                                                 lint,
                                                 level,
@@ -248,7 +250,8 @@ impl<'a> LintLevelsBuilder<'a> {
                         let lint = builtin::UNKNOWN_LINTS;
                         let (level, src) = self.sets.get_lint_level(lint,
                                                                     self.cur,
-                                                                    Some(&specs));
+                                                                    Some(&specs),
+                                                                    self.sess);
                         let msg = format!("unknown lint: `{}`", name);
                         let mut db = lint::struct_lint_level(self.sess,
                                                 lint,
@@ -342,7 +345,7 @@ impl<'a> LintLevelsBuilder<'a> {
                        msg: &str)
         -> DiagnosticBuilder<'a>
     {
-        let (level, src) = self.sets.get_lint_level(lint, self.cur, None);
+        let (level, src) = self.sets.get_lint_level(lint, self.cur, None, self.sess);
         lint::struct_lint_level(self.sess, lint, level, src, span, msg)
     }
 
@@ -377,11 +380,11 @@ impl LintLevelMap {
     /// If the `id` was not previously registered, returns `None`. If `None` is
     /// returned then the parent of `id` should be acquired and this function
     /// should be called again.
-    pub fn level_and_source(&self, lint: &'static Lint, id: HirId)
+    pub fn level_and_source(&self, lint: &'static Lint, id: HirId, session: &Session)
         -> Option<(Level, LintSource)>
     {
         self.id_to_set.get(&id).map(|idx| {
-            self.sets.get_lint_level(lint, *idx, None)
+            self.sets.get_lint_level(lint, *idx, None, session)
         })
     }
 
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index b2a9859f68a3e..e28cc9c201d02 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -37,7 +37,7 @@ use errors::{DiagnosticBuilder, DiagnosticId};
 use hir::def_id::{CrateNum, LOCAL_CRATE};
 use hir::intravisit::{self, FnKind};
 use hir;
-use session::{Session, DiagnosticMessageId};
+use session::{config, Session, DiagnosticMessageId};
 use std::hash;
 use syntax::ast;
 use syntax::codemap::MultiSpan;
@@ -74,6 +74,9 @@ pub struct Lint {
     ///
     /// e.g. "imports that are never used"
     pub desc: &'static str,
+
+    /// Deny lint after this epoch
+    pub epoch_deny: Option<config::Epoch>,
 }
 
 impl Lint {
@@ -81,18 +84,36 @@ impl Lint {
     pub fn name_lower(&self) -> String {
         self.name.to_ascii_lowercase()
     }
+
+    pub fn default_level(&self, session: &Session) -> Level {
+        if let Some(epoch_deny) = self.epoch_deny {
+            if session.epoch() >= epoch_deny {
+                return Level::Deny
+            }
+        }
+        self.default_level
+    }
 }
 
 /// Declare a static item of type `&'static Lint`.
 #[macro_export]
 macro_rules! declare_lint {
+    ($vis: vis $NAME: ident, $Level: ident, $desc: expr, $epoch: expr) => (
+        $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
+            name: stringify!($NAME),
+            default_level: $crate::lint::$Level,
+            desc: $desc,
+            epoch_deny: Some($epoch)
+        };
+    );
     ($vis: vis $NAME: ident, $Level: ident, $desc: expr) => (
         $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
             name: stringify!($NAME),
             default_level: $crate::lint::$Level,
-            desc: $desc
+            desc: $desc,
+            epoch_deny: None,
         };
-    )
+    );
 }
 
 /// Declare a static `LintArray` and return it as an expression.
@@ -304,7 +325,7 @@ impl LintId {
 /// Setting for how to handle a lint.
 #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
 pub enum Level {
-    Allow, Warn, Deny, Forbid
+    Allow, Warn, Deny, Forbid,
 }
 
 impl_stable_hash_for!(enum self::Level {
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index ef85ef8e37e70..beb828ab91bf7 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -113,7 +113,7 @@ pub enum OutputType {
 }
 
 /// The epoch of the compiler (RFC 2052)
-#[derive(Clone, Copy, Hash, PartialOrd, Ord, Eq, PartialEq)]
+#[derive(Clone, Copy, Hash, PartialOrd, Ord, Eq, PartialEq, Debug)]
 #[non_exhaustive]
 pub enum Epoch {
     // epochs must be kept in order, newest to oldest
@@ -148,6 +148,15 @@ impl ToString for Epoch {
     }
 }
 
+impl Epoch {
+    pub fn lint_name(&self) -> &'static str {
+        match *self {
+            Epoch::Epoch2015 => "epoch_2015",
+            Epoch::Epoch2018 => "epoch_2018",
+        }
+    }
+}
+
 impl str::FromStr for Epoch {
     type Err = ();
     fn from_str(s: &str) -> Result<Self, ()> {
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 9d7a9acc3d533..6901674a6cf8d 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -869,6 +869,10 @@ impl Session {
     pub fn rust_2018(&self) -> bool {
         self.opts.debugging_opts.epoch >= Epoch::Epoch2018
     }
+
+    pub fn epoch(&self) -> Epoch {
+        self.opts.debugging_opts.epoch
+    }
 }
 
 pub fn build_session(sopts: config::Options,
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index e4e07454c97ac..414ddb9efb2c2 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -2234,7 +2234,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             let sets = self.lint_levels(LOCAL_CRATE);
             loop {
                 let hir_id = self.hir.definitions().node_to_hir_id(id);
-                if let Some(pair) = sets.level_and_source(lint, hir_id) {
+                if let Some(pair) = sets.level_and_source(lint, hir_id, self.sess) {
                     return pair
                 }
                 let next = self.hir.get_parent_node(id);
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index b8a1fe9910540..943d690d76710 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -735,7 +735,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session,
 
     // Lint plugins are registered; now we can process command line flags.
     if sess.opts.describe_lints {
-        super::describe_lints(&sess.lint_store.borrow(), true);
+        super::describe_lints(&sess, &sess.lint_store.borrow(), true);
         return Err(CompileIncomplete::Stopped);
     }
 
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 05dcaf731352a..5f0d106877c08 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -774,15 +774,15 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
                 -> Option<(Input, Option<PathBuf>)> {
         match matches.free.len() {
             0 => {
+                let mut sess = build_session(sopts.clone(),
+                    None,
+                    descriptions.clone());
                 if sopts.describe_lints {
                     let mut ls = lint::LintStore::new();
-                    rustc_lint::register_builtins(&mut ls, None);
-                    describe_lints(&ls, false);
+                    rustc_lint::register_builtins(&mut ls, Some(&sess));
+                    describe_lints(&sess, &ls, false);
                     return None;
                 }
-                let mut sess = build_session(sopts.clone(),
-                    None,
-                    descriptions.clone());
                 rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
                 let mut cfg = config::build_configuration(&sess, cfg.clone());
                 let trans = get_trans(&sess);
@@ -1121,7 +1121,7 @@ fn usage(verbose: bool, include_unstable_options: bool) {
              verbose_help);
 }
 
-fn describe_lints(lint_store: &lint::LintStore, loaded_plugins: bool) {
+fn describe_lints(sess: &Session, lint_store: &lint::LintStore, loaded_plugins: bool) {
     println!("
 Available lint options:
     -W <foo>           Warn about <foo>
@@ -1133,10 +1133,10 @@ Available lint options:
 
 ");
 
-    fn sort_lints(lints: Vec<(&'static Lint, bool)>) -> Vec<&'static Lint> {
+    fn sort_lints(sess: &Session, lints: Vec<(&'static Lint, bool)>) -> Vec<&'static Lint> {
         let mut lints: Vec<_> = lints.into_iter().map(|(x, _)| x).collect();
         lints.sort_by(|x: &&Lint, y: &&Lint| {
-            match x.default_level.cmp(&y.default_level) {
+            match x.default_level(sess).cmp(&y.default_level(sess)) {
                 // The sort doesn't case-fold but it's doubtful we care.
                 Equal => x.name.cmp(y.name),
                 r => r,
@@ -1159,8 +1159,8 @@ Available lint options:
                                                    .iter()
                                                    .cloned()
                                                    .partition(|&(_, p)| p);
-    let plugin = sort_lints(plugin);
-    let builtin = sort_lints(builtin);
+    let plugin = sort_lints(sess, plugin);
+    let builtin = sort_lints(sess, builtin);
 
     let (plugin_groups, builtin_groups): (Vec<_>, _) = lint_store.get_lint_groups()
                                                                  .iter()
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 699765dde03ff..c35a3fbe419d1 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -185,74 +185,92 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
         FutureIncompatibleInfo {
             id: LintId::of(PRIVATE_IN_PUBLIC),
             reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
+            epoch: None,
         },
         FutureIncompatibleInfo {
             id: LintId::of(PUB_USE_OF_PRIVATE_EXTERN_CRATE),
             reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
+            epoch: None,
         },
         FutureIncompatibleInfo {
             id: LintId::of(PATTERNS_IN_FNS_WITHOUT_BODY),
             reference: "issue #35203 <https://github.com/rust-lang/rust/issues/35203>",
+            epoch: None,
         },
         FutureIncompatibleInfo {
             id: LintId::of(SAFE_EXTERN_STATICS),
             reference: "issue #36247 <https://github.com/rust-lang/rust/issues/36247>",
+            epoch: None,
         },
         FutureIncompatibleInfo {
             id: LintId::of(INVALID_TYPE_PARAM_DEFAULT),
             reference: "issue #36887 <https://github.com/rust-lang/rust/issues/36887>",
+            epoch: None,
         },
         FutureIncompatibleInfo {
             id: LintId::of(LEGACY_DIRECTORY_OWNERSHIP),
             reference: "issue #37872 <https://github.com/rust-lang/rust/issues/37872>",
+            epoch: None,
         },
         FutureIncompatibleInfo {
             id: LintId::of(LEGACY_IMPORTS),
             reference: "issue #38260 <https://github.com/rust-lang/rust/issues/38260>",
+            epoch: None,
         },
         FutureIncompatibleInfo {
             id: LintId::of(LEGACY_CONSTRUCTOR_VISIBILITY),
             reference: "issue #39207 <https://github.com/rust-lang/rust/issues/39207>",
+            epoch: None,
         },
         FutureIncompatibleInfo {
             id: LintId::of(RESOLVE_TRAIT_ON_DEFAULTED_UNIT),
             reference: "issue #39216 <https://github.com/rust-lang/rust/issues/39216>",
+            epoch: None,
         },
         FutureIncompatibleInfo {
             id: LintId::of(MISSING_FRAGMENT_SPECIFIER),
             reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>",
+            epoch: None,
         },
         FutureIncompatibleInfo {
             id: LintId::of(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN),
             reference: "issue #41620 <https://github.com/rust-lang/rust/issues/41620>",
+            epoch: None,
         },
         FutureIncompatibleInfo {
             id: LintId::of(ANONYMOUS_PARAMETERS),
             reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>",
+            epoch: None,
         },
         FutureIncompatibleInfo {
             id: LintId::of(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES),
             reference: "issue #42238 <https://github.com/rust-lang/rust/issues/42238>",
+            epoch: None,
         },
         FutureIncompatibleInfo {
             id: LintId::of(LATE_BOUND_LIFETIME_ARGUMENTS),
             reference: "issue #42868 <https://github.com/rust-lang/rust/issues/42868>",
+            epoch: None,
         },
         FutureIncompatibleInfo {
             id: LintId::of(SAFE_PACKED_BORROWS),
             reference: "issue #46043 <https://github.com/rust-lang/rust/issues/46043>",
+            epoch: None,
         },
         FutureIncompatibleInfo {
             id: LintId::of(INCOHERENT_FUNDAMENTAL_IMPLS),
             reference: "issue #46205 <https://github.com/rust-lang/rust/issues/46205>",
+            epoch: None,
         },
         FutureIncompatibleInfo {
             id: LintId::of(COERCE_NEVER),
             reference: "issue #46325 <https://github.com/rust-lang/rust/issues/46325>",
+            epoch: None,
         },
         FutureIncompatibleInfo {
             id: LintId::of(TYVAR_BEHIND_RAW_POINTER),
             reference: "issue #46906 <https://github.com/rust-lang/rust/issues/46906>",
+            epoch: None,
         },
         ]);
 

From 3eeabe7b7d13f8ca2d29e117f45cd420d6f73da4 Mon Sep 17 00:00:00 2001
From: Manish Goregaokar <manishsmail@gmail.com>
Date: Thu, 22 Feb 2018 22:14:08 -0800
Subject: [PATCH 06/14] Add hardwired lint for dyn trait

---
 src/librustc/lint/builtin.rs | 12 ++++++++++--
 src/librustc_lint/lib.rs     |  5 +++++
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 0577800f3f411..2b1ff8a0e7881 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -15,6 +15,7 @@
 //! lints are all available in `rustc_lint::builtin`.
 
 use lint::{LintPass, LateLintPass, LintArray};
+use session::config::Epoch;
 
 declare_lint! {
     pub CONST_ERR,
@@ -252,6 +253,13 @@ declare_lint! {
     "hidden lifetime parameters are deprecated, try `Foo<'_>`"
 }
 
+declare_lint! {
+    pub BARE_TRAIT_OBJECT,
+    Warn,
+    "suggest using `dyn Trait` for trait objects",
+    Epoch::Epoch2018
+}
+
 /// Does nothing as a lint pass, but registers some `Lint`s
 /// which are used by other parts of the compiler.
 #[derive(Copy, Clone)]
@@ -298,8 +306,8 @@ impl LintPass for HardwiredLints {
             COERCE_NEVER,
             SINGLE_USE_LIFETIME,
             TYVAR_BEHIND_RAW_POINTER,
-            ELIDED_LIFETIME_IN_PATH
-
+            ELIDED_LIFETIME_IN_PATH,
+            BARE_TRAIT_OBJECT
         )
     }
 }
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index c35a3fbe419d1..c162b8409af6a 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -272,6 +272,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
             reference: "issue #46906 <https://github.com/rust-lang/rust/issues/46906>",
             epoch: None,
         },
+         FutureIncompatibleInfo {
+             id: LintId::of(lint::builtin::BARE_TRAIT_OBJECT),
+             reference: "issue #48457 <https://github.com/rust-lang/rust/issues/48457>",
+             epoch: Some(session::config::Epoch::Epoch2018),
+         }
         ]);
 
     // Register renamed and removed lints

From bd29696218c9363d0e6dff7824c53f040eab76fc Mon Sep 17 00:00:00 2001
From: Manish Goregaokar <manishsmail@gmail.com>
Date: Thu, 22 Feb 2018 22:34:06 -0800
Subject: [PATCH 07/14] Add ability for hardwired lints to operate on the
 diagnostic builder

---
 src/librustc/lint/builtin.rs | 26 ++++++++++++++++++++++++++
 src/librustc/lint/context.rs | 19 ++++++++++++++++---
 src/librustc/lint/mod.rs     |  5 ++++-
 src/librustc/session/mod.rs  | 14 +++++++++++++-
 4 files changed, 59 insertions(+), 5 deletions(-)

diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 2b1ff8a0e7881..cc7c5dc06660c 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -14,8 +14,11 @@
 //! compiler code, rather than using their own custom pass. Those
 //! lints are all available in `rustc_lint::builtin`.
 
+use errors::DiagnosticBuilder;
 use lint::{LintPass, LateLintPass, LintArray};
+use session::Session;
 use session::config::Epoch;
+use syntax::codemap::Span;
 
 declare_lint! {
     pub CONST_ERR,
@@ -312,4 +315,27 @@ impl LintPass for HardwiredLints {
     }
 }
 
+// this could be a closure, but then implementing derive traits
+// becomes hacky (and it gets allocated)
+#[derive(PartialEq, RustcEncodable, RustcDecodable, Debug)]
+pub enum BuiltinLintDiagnostics {
+    Normal,
+    BareTraitObject(Span)
+}
+
+impl BuiltinLintDiagnostics {
+    pub fn run(self, sess: &Session, db: &mut DiagnosticBuilder) {
+        match self {
+            BuiltinLintDiagnostics::Normal => (),
+            BuiltinLintDiagnostics::BareTraitObject(span) => {
+                let sugg = match sess.codemap().span_to_snippet(span) {
+                    Ok(s) => format!("dyn {}", s),
+                    Err(_) => format!("dyn <type>")
+                };
+                db.span_suggestion(span, "use `dyn`", sugg);
+            }
+        }
+    }
+}
+
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HardwiredLints {}
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 870b52c221f37..a9c023d14309d 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -29,6 +29,7 @@ use self::TargetLint::*;
 use std::slice;
 use lint::{EarlyLintPassObject, LateLintPassObject};
 use lint::{Level, Lint, LintId, LintPass, LintBuffer};
+use lint::builtin::BuiltinLintDiagnostics;
 use lint::levels::{LintLevelSets, LintLevelsBuilder};
 use middle::privacy::AccessLevels;
 use rustc_serialize::{Decoder, Decodable, Encoder, Encodable};
@@ -92,6 +93,7 @@ pub struct BufferedEarlyLint {
     pub ast_id: ast::NodeId,
     pub span: MultiSpan,
     pub msg: String,
+    pub diagnostic: BuiltinLintDiagnostics,
 }
 
 /// Extra information for a future incompatibility lint. See the call
@@ -446,6 +448,16 @@ pub trait LintContext<'tcx>: Sized {
         self.lookup(lint, span, msg).emit();
     }
 
+    fn lookup_and_emit_with_diagnostics<S: Into<MultiSpan>>(&self,
+                                                            lint: &'static Lint,
+                                                            span: Option<S>,
+                                                            msg: &str,
+                                                            diagnostic: BuiltinLintDiagnostics) {
+        let mut db = self.lookup(lint, span, msg);
+        diagnostic.run(self.sess(), &mut db);
+        db.emit();
+    }
+
     fn lookup<S: Into<MultiSpan>>(&self,
                                   lint: &'static Lint,
                                   span: Option<S>,
@@ -516,9 +528,10 @@ impl<'a> EarlyContext<'a> {
 
     fn check_id(&mut self, id: ast::NodeId) {
         for early_lint in self.buffered.take(id) {
-            self.lookup_and_emit(early_lint.lint_id.lint,
-                                 Some(early_lint.span.clone()),
-                                 &early_lint.msg);
+            self.lookup_and_emit_with_diagnostics(early_lint.lint_id.lint,
+                                                  Some(early_lint.span.clone()),
+                                                  &early_lint.msg,
+                                                  early_lint.diagnostic);
         }
     }
 }
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index e28cc9c201d02..a51d06c06edd3 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -37,6 +37,7 @@ use errors::{DiagnosticBuilder, DiagnosticId};
 use hir::def_id::{CrateNum, LOCAL_CRATE};
 use hir::intravisit::{self, FnKind};
 use hir;
+use lint::builtin::BuiltinLintDiagnostics;
 use session::{config, Session, DiagnosticMessageId};
 use std::hash;
 use syntax::ast;
@@ -399,12 +400,14 @@ impl LintBuffer {
                     lint: &'static Lint,
                     id: ast::NodeId,
                     sp: MultiSpan,
-                    msg: &str) {
+                    msg: &str,
+                    diagnostic: BuiltinLintDiagnostics) {
         let early_lint = BufferedEarlyLint {
             lint_id: LintId::of(lint),
             ast_id: id,
             span: sp,
             msg: msg.to_string(),
+            diagnostic
         };
         let arr = self.map.entry(id).or_insert(Vec::new());
         if !arr.contains(&early_lint) {
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 6901674a6cf8d..7041efbd5bc5e 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -16,6 +16,7 @@ use ich::Fingerprint;
 
 use ich;
 use lint;
+use lint::builtin::BuiltinLintDiagnostics;
 use middle::allocator::AllocatorKind;
 use middle::dependency_format;
 use session::search_paths::PathKind;
@@ -341,7 +342,18 @@ impl Session {
                                            sp: S,
                                            msg: &str) {
         match *self.buffered_lints.borrow_mut() {
-            Some(ref mut buffer) => buffer.add_lint(lint, id, sp.into(), msg),
+            Some(ref mut buffer) => buffer.add_lint(lint, id, sp.into(),
+                                                    msg, BuiltinLintDiagnostics::Normal),
+            None => bug!("can't buffer lints after HIR lowering"),
+        }
+    }
+
+    pub fn buffer_lint_with_diagnostic<S: Into<MultiSpan>>(&self,
+        lint: &'static lint::Lint, id: ast::NodeId, sp: S,
+        msg: &str, diagnostic: BuiltinLintDiagnostics) {
+        match *self.buffered_lints.borrow_mut() {
+            Some(ref mut buffer) => buffer.add_lint(lint, id, sp.into(),
+                                                    msg, diagnostic),
             None => bug!("can't buffer lints after HIR lowering"),
         }
     }

From 63168f72756da88c7488865160c7dfbd446bb0aa Mon Sep 17 00:00:00 2001
From: Manish Goregaokar <manishsmail@gmail.com>
Date: Thu, 22 Feb 2018 22:44:44 -0800
Subject: [PATCH 08/14] Lint bare traits

---
 src/librustc/hir/lowering.rs | 24 ++++++++++++++++++++----
 src/librustc/lib.rs          |  2 ++
 src/librustc_mir/lib.rs      |  1 +
 3 files changed, 23 insertions(+), 4 deletions(-)

diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 55dcb16c3c95f..aeccf133fa86a 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -46,7 +46,7 @@ use hir::HirVec;
 use hir::map::{Definitions, DefKey, DefPathData};
 use hir::def_id::{DefIndex, DefId, CRATE_DEF_INDEX, DefIndexAddressSpace};
 use hir::def::{Def, PathResolution};
-use lint::builtin::PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES;
+use lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES};
 use middle::cstore::CrateStore;
 use rustc_data_structures::indexed_vec::IndexVec;
 use session::Session;
@@ -912,7 +912,11 @@ impl<'a> LoweringContext<'a> {
             TyKind::Path(ref qself, ref path) => {
                 let id = self.lower_node_id(t.id);
                 let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit, itctx);
-                return self.ty_path(id, t.span, qpath);
+                let ty = self.ty_path(id, t.span, qpath);
+                if let hir::TyTraitObject(..) = ty.node {
+                    self.maybe_lint_bare_trait(t.span, t.id);
+                }
+                return ty;
             }
             TyKind::ImplicitSelf => {
                 hir::TyPath(hir::QPath::Resolved(None, P(hir::Path {
@@ -931,7 +935,7 @@ impl<'a> LoweringContext<'a> {
                 let expr = self.lower_body(None, |this| this.lower_expr(expr));
                 hir::TyTypeof(expr)
             }
-            TyKind::TraitObject(ref bounds, ..) => {
+            TyKind::TraitObject(ref bounds, kind) => {
                 let mut lifetime_bound = None;
                 let bounds = bounds.iter().filter_map(|bound| {
                     match *bound {
@@ -950,6 +954,9 @@ impl<'a> LoweringContext<'a> {
                 let lifetime_bound = lifetime_bound.unwrap_or_else(|| {
                     self.elided_lifetime(t.span)
                 });
+                if kind != TraitObjectSyntax::Dyn {
+                    self.maybe_lint_bare_trait(t.span, t.id);
+                }
                 hir::TyTraitObject(bounds, lifetime_bound)
             }
             TyKind::ImplTrait(ref bounds) => {
@@ -3685,7 +3692,6 @@ impl<'a> LoweringContext<'a> {
                     // The original ID is taken by the `PolyTraitRef`,
                     // so the `Ty` itself needs a different one.
                     id = self.next_id();
-
                     hir::TyTraitObject(hir_vec![principal], self.elided_lifetime(span))
                 } else {
                     hir::TyPath(hir::QPath::Resolved(None, path))
@@ -3703,6 +3709,16 @@ impl<'a> LoweringContext<'a> {
             name: hir::LifetimeName::Implicit,
         }
     }
+
+    fn maybe_lint_bare_trait(&self, span: Span, id: NodeId) {
+        if self.sess.features.borrow().dyn_trait {
+            self.sess.buffer_lint_with_diagnostic(
+                builtin::BARE_TRAIT_OBJECT, id, span,
+                "trait objects without an explicit `dyn` are deprecated",
+                builtin::BuiltinLintDiagnostics::BareTraitObject(span)
+            )
+        }
+    }
 }
 
 fn body_ids(bodies: &BTreeMap<hir::BodyId, hir::Body>) -> Vec<hir::BodyId> {
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index a7a2619505931..e1ca4665df8bb 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -40,6 +40,8 @@
        html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![deny(warnings)]
 
+#![cfg_attr(not(stage0), allow(bare_trait_object))]
+
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(conservative_impl_trait)]
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index 1699ad0f19cf6..7905065bc1d8f 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -15,6 +15,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
 */
 
 #![deny(warnings)]
+#![cfg_attr(not(stage0), allow(bare_trait_object))]
 
 #![feature(box_patterns)]
 #![feature(box_syntax)]

From 177271f91401852841c647ae01b4072253d69234 Mon Sep 17 00:00:00 2001
From: Manish Goregaokar <manishsmail@gmail.com>
Date: Fri, 23 Feb 2018 00:10:37 -0800
Subject: [PATCH 09/14] span_bug doesn't work well at this stage, use the
 session directly

---
 src/librustc/lint/context.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index a9c023d14309d..bfd2034dd6cfe 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -1084,7 +1084,7 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) {
     if !sess.opts.actually_rustdoc {
         for (_id, lints) in cx.buffered.map {
             for early_lint in lints {
-                span_bug!(early_lint.span, "failed to process buffered lint here");
+                sess.delay_span_bug(early_lint.span, "failed to process buffered lint here");
             }
         }
     }

From dd67fe17276e4bf8cd054d2a8453dc58e0571447 Mon Sep 17 00:00:00 2001
From: Manish Goregaokar <manishsmail@gmail.com>
Date: Fri, 23 Feb 2018 13:00:11 -0800
Subject: [PATCH 10/14] Silence warning in test

---
 src/test/compile-fail/trait-bounds-not-on-struct.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/test/compile-fail/trait-bounds-not-on-struct.rs b/src/test/compile-fail/trait-bounds-not-on-struct.rs
index 6cd439167314b..0dd1a4e7d7335 100644
--- a/src/test/compile-fail/trait-bounds-not-on-struct.rs
+++ b/src/test/compile-fail/trait-bounds-not-on-struct.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 #![feature(dyn_trait)]
+#![allow(bare_trait_object)]
 
 struct Foo;
 

From 12c7e273309e7fb3c8309e0d6217d96baa7cbc89 Mon Sep 17 00:00:00 2001
From: Mikhail Modin <mikhailm1@gmail.com>
Date: Mon, 19 Feb 2018 19:42:00 +0300
Subject: [PATCH 11/14] restore Subslice move out from array after elaborate
 drops and borrowck

---
 src/librustc_mir/transform/mod.rs             |   1 +
 .../transform/uniform_array_move_out.rs       | 198 +++++++++++++++++-
 src/test/mir-opt/uniform_array_move_out.rs    |  25 +++
 3 files changed, 213 insertions(+), 11 deletions(-)

diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 7ed250e94c52f..f721cdf714dca 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -257,6 +257,7 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx
 
 
         // Optimizations begin.
+        uniform_array_move_out::RestoreSubsliceArrayMoveOut,
         inline::Inline,
         instcombine::InstCombine,
         deaggregator::Deaggregator,
diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs
index 0db5ecf0eb270..e46de17047986 100644
--- a/src/librustc_mir/transform/uniform_array_move_out.rs
+++ b/src/librustc_mir/transform/uniform_array_move_out.rs
@@ -34,15 +34,15 @@
 //  and mir statement _11 = move _2[-1 of 1]; replaced by:
 //  _11 = move _2[2 of 3];
 //
-// FIXME: convert to Subslice back for performance reason
 // FIXME: integrate this transformation to the mir build
 
 use rustc::ty;
 use rustc::ty::TyCtxt;
 use rustc::mir::*;
-use rustc::mir::visit::Visitor;
+use rustc::mir::visit::{Visitor, PlaceContext};
 use transform::{MirPass, MirSource};
 use util::patch::MirPatch;
+use rustc_data_structures::indexed_vec::{IndexVec};
 
 pub struct UniformArrayMoveOut;
 
@@ -67,12 +67,12 @@ struct UniformArrayMoveOutVisitor<'a, 'tcx: 'a> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
-    fn visit_statement(&mut self,
-                       block: BasicBlock,
-                       statement: &Statement<'tcx>,
-                       location: Location) {
-        if let StatementKind::Assign(ref dst_place,
-                                     Rvalue::Use(Operand::Move(ref src_place))) = statement.kind {
+    fn visit_assign(&mut self,
+                    block: BasicBlock,
+                    dst_place: &Place<'tcx>,
+                    rvalue: &Rvalue<'tcx>,
+                    location: Location) {
+        if let Rvalue::Use(Operand::Move(ref src_place)) = rvalue {
             if let Place::Projection(ref proj) = *src_place {
                 if let ProjectionElem::ConstantIndex{offset: _,
                                                      min_length: _,
@@ -92,7 +92,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
                 }
             }
         }
-        return self.super_statement(block, statement, location);
+        self.super_assign(block, dst_place, rvalue, location)
     }
 }
 
@@ -104,7 +104,7 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
                item_ty: &'tcx ty::TyS<'tcx>,
                size: u32) {
         match proj.elem {
-            // uniform _10 = move _2[:-1];
+            // uniforms statements like_10 = move _2[:-1];
             ProjectionElem::Subslice{from, to} => {
                 self.patch.make_nop(location);
                 let temps : Vec<_> = (from..(size-to)).map(|i| {
@@ -133,7 +133,7 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
                     self.patch.add_statement(location, StatementKind::StorageDead(temp));
                 }
             }
-            // _11 = move _2[-1 of 1];
+            // uniforms statements like _11 = move _2[-1 of 1];
             ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true} => {
                 self.patch.make_nop(location);
                 self.patch.add_assign(location,
@@ -151,3 +151,179 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
         }
     }
 }
+
+// Restore Subslice move out after analysis
+// Example:
+//
+//  next statements:
+//   StorageLive(_12);
+//   _12 = move _2[0 of 3];
+//   StorageLive(_13);
+//   _13 = move _2[1 of 3];
+//   _10 = [move _12, move _13]
+//   StorageDead(_12);
+//   StorageDead(_13);
+//
+// replaced by _10 = move _2[:-1];
+
+pub struct RestoreSubsliceArrayMoveOut;
+
+impl MirPass for RestoreSubsliceArrayMoveOut {
+    fn run_pass<'a, 'tcx>(&self,
+                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          _src: MirSource,
+                          mir: &mut Mir<'tcx>) {
+        let mut patch = MirPatch::new(mir);
+        {
+            let mut visitor = RestoreDataCollector {
+                locals_use: IndexVec::from_elem(LocalUse::new(), &mir.local_decls),
+                candidates: vec![],
+            };
+            visitor.visit_mir(mir);
+
+            for candidate in &visitor.candidates {
+                let statement = &mir[candidate.block].statements[candidate.statement_index];
+                if let StatementKind::Assign(ref dst_place, ref rval) = statement.kind {
+                    if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = *rval {
+                        let items : Vec<_> = items.iter().map(|item| {
+                            if let Operand::Move(Place::Local(local)) = item {
+                                let local_use = &visitor.locals_use[*local];
+                                let opt_index_and_place = Self::try_get_item_source(local_use, mir);
+                                // each local should be used twice:
+                                //  in assign and in aggregate statments
+                                if local_use.use_count == 2 && opt_index_and_place.is_some() {
+                                    let (index, src_place) = opt_index_and_place.unwrap();
+                                    return Some((local_use, index, src_place));
+                                }
+                            }
+                            None
+                        }).collect();
+
+                        let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2);
+                        let opt_size = opt_src_place.and_then(|src_place| {
+                            let src_ty = src_place.ty(mir, tcx).to_ty(tcx);
+                            if let ty::TyArray(_, ref size_o) = src_ty.sty {
+                                size_o.val.to_const_int().and_then(|v| v.to_u64())
+                            } else {
+                                None
+                            }
+                        });
+                        Self::check_and_patch(*candidate, &items, opt_size, &mut patch, dst_place);
+                    }
+                }
+            }
+        }
+        patch.apply(mir);
+    }
+}
+
+impl RestoreSubsliceArrayMoveOut {
+    // Checks that source has size, all locals are inited from same source place and
+    // indices is an integer interval. If all checks pass do the replacent.
+    // items are Vec<Option<LocalUse, index in source array, source place for init local>>
+    fn check_and_patch<'tcx>(candidate: Location,
+                             items: &Vec<Option<(&LocalUse, u32, &Place<'tcx>)>>,
+                             opt_size: Option<u64>,
+                             patch: &mut MirPatch<'tcx>,
+                             dst_place: &Place<'tcx>) {
+        let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2);
+
+        if opt_size.is_some() && items.iter().all(
+            |l| l.is_some() && l.unwrap().2 == opt_src_place.unwrap()) {
+
+            let indicies: Vec<_> = items.iter().map(|x| x.unwrap().1).collect();
+            for i in 1..indicies.len() {
+                if indicies[i - 1] + 1 != indicies[i] {
+                    return;
+                }
+            }
+
+            let min = *indicies.first().unwrap();
+            let max = *indicies.last().unwrap();
+
+            for item in items {
+                let locals_use = item.unwrap().0;
+                patch.make_nop(locals_use.alive.unwrap());
+                patch.make_nop(locals_use.dead.unwrap());
+                patch.make_nop(locals_use.first_use.unwrap());
+            }
+            patch.make_nop(candidate);
+            let size = opt_size.unwrap() as u32;
+            patch.add_assign(candidate,
+                             dst_place.clone(),
+                             Rvalue::Use(
+                                 Operand::Move(
+                                     Place::Projection(box PlaceProjection{
+                                         base: opt_src_place.unwrap().clone(),
+                                         elem: ProjectionElem::Subslice{
+                                             from: min, to: size - max - 1}}))));
+        }
+    }
+
+    fn try_get_item_source<'a, 'tcx>(local_use: &LocalUse,
+                                     mir: &'a Mir<'tcx>) -> Option<(u32, &'a Place<'tcx>)> {
+        if let Some(location) = local_use.first_use {
+            let block = &mir[location.block];
+            if block.statements.len() > location.statement_index {
+                let statement = &block.statements[location.statement_index];
+                if let StatementKind::Assign(
+                    Place::Local(_),
+                    Rvalue::Use(Operand::Move(Place::Projection(box PlaceProjection{
+                        ref base, elem: ProjectionElem::ConstantIndex{
+                            offset, min_length: _, from_end: false}})))) = statement.kind {
+                    return Some((offset, base))
+                }
+            }
+        }
+        None
+    }
+}
+
+#[derive(Copy, Clone, Debug)]
+struct LocalUse {
+    alive: Option<Location>,
+    dead: Option<Location>,
+    use_count: u32,
+    first_use: Option<Location>,
+}
+
+impl LocalUse {
+    pub fn new() -> Self {
+        LocalUse{alive: None, dead: None, use_count: 0, first_use: None}
+    }
+}
+
+struct RestoreDataCollector {
+    locals_use: IndexVec<Local, LocalUse>,
+    candidates: Vec<Location>,
+}
+
+impl<'tcx> Visitor<'tcx> for RestoreDataCollector {
+    fn visit_assign(&mut self,
+                    block: BasicBlock,
+                    place: &Place<'tcx>,
+                    rvalue: &Rvalue<'tcx>,
+                    location: Location) {
+        if let Rvalue::Aggregate(box AggregateKind::Array(_), _) = *rvalue {
+            self.candidates.push(location);
+        }
+        self.super_assign(block, place, rvalue, location)
+    }
+
+    fn visit_local(&mut self,
+                   local: &Local,
+                   context: PlaceContext<'tcx>,
+                   location: Location) {
+        let local_use = &mut self.locals_use[*local];
+        match context {
+            PlaceContext::StorageLive => local_use.alive = Some(location),
+            PlaceContext::StorageDead => local_use.dead = Some(location),
+            _ => {
+                local_use.use_count += 1;
+                if local_use.first_use.is_none() {
+                    local_use.first_use = Some(location);
+                }
+            }
+        }
+    }
+}
diff --git a/src/test/mir-opt/uniform_array_move_out.rs b/src/test/mir-opt/uniform_array_move_out.rs
index 4a310255aac57..482b69a59ddbc 100644
--- a/src/test/mir-opt/uniform_array_move_out.rs
+++ b/src/test/mir-opt/uniform_array_move_out.rs
@@ -57,3 +57,28 @@ fn main() {
 //     nop;
 //     _0 = ();
 // END rustc.move_out_by_subslice.UniformArrayMoveOut.after.mir
+
+// START rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.before.mir
+//     StorageLive(_6);
+//     StorageLive(_7);
+//     _7 = move _1[0 of 2];
+//     StorageLive(_8);
+//     _8 = move _1[1 of 2];
+//     _6 = [move _7, move _8];
+//     StorageDead(_7);
+//     StorageDead(_8);
+//     _0 = ();
+// END rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.before.mir
+
+// START rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.after.mir
+//     StorageLive(_6);
+//     nop;
+//     nop;
+//     nop;
+//     nop;
+//     _6 = move _1[0:];
+//     nop;
+//     nop;
+//     nop;
+//     _0 = ();
+// END rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.after.mir

From 0cb367266b0a336c0a18ae999beeadd3235961a2 Mon Sep 17 00:00:00 2001
From: Manish Goregaokar <manishsmail@gmail.com>
Date: Fri, 23 Feb 2018 13:52:28 -0800
Subject: [PATCH 12/14] Emit parentheses in suggestion for global paths

---
 src/librustc/hir/lowering.rs | 8 ++++----
 src/librustc/lint/builtin.rs | 5 +++--
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index aeccf133fa86a..9d4011fa7ad9f 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -914,7 +914,7 @@ impl<'a> LoweringContext<'a> {
                 let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit, itctx);
                 let ty = self.ty_path(id, t.span, qpath);
                 if let hir::TyTraitObject(..) = ty.node {
-                    self.maybe_lint_bare_trait(t.span, t.id);
+                    self.maybe_lint_bare_trait(t.span, t.id, qself.is_none() && path.is_global());
                 }
                 return ty;
             }
@@ -955,7 +955,7 @@ impl<'a> LoweringContext<'a> {
                     self.elided_lifetime(t.span)
                 });
                 if kind != TraitObjectSyntax::Dyn {
-                    self.maybe_lint_bare_trait(t.span, t.id);
+                    self.maybe_lint_bare_trait(t.span, t.id, false);
                 }
                 hir::TyTraitObject(bounds, lifetime_bound)
             }
@@ -3710,12 +3710,12 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn maybe_lint_bare_trait(&self, span: Span, id: NodeId) {
+    fn maybe_lint_bare_trait(&self, span: Span, id: NodeId, is_global: bool) {
         if self.sess.features.borrow().dyn_trait {
             self.sess.buffer_lint_with_diagnostic(
                 builtin::BARE_TRAIT_OBJECT, id, span,
                 "trait objects without an explicit `dyn` are deprecated",
-                builtin::BuiltinLintDiagnostics::BareTraitObject(span)
+                builtin::BuiltinLintDiagnostics::BareTraitObject(span, is_global)
             )
         }
     }
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index cc7c5dc06660c..b68b7dc6c0672 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -320,15 +320,16 @@ impl LintPass for HardwiredLints {
 #[derive(PartialEq, RustcEncodable, RustcDecodable, Debug)]
 pub enum BuiltinLintDiagnostics {
     Normal,
-    BareTraitObject(Span)
+    BareTraitObject(Span, /* is_global */ bool)
 }
 
 impl BuiltinLintDiagnostics {
     pub fn run(self, sess: &Session, db: &mut DiagnosticBuilder) {
         match self {
             BuiltinLintDiagnostics::Normal => (),
-            BuiltinLintDiagnostics::BareTraitObject(span) => {
+            BuiltinLintDiagnostics::BareTraitObject(span, is_global) => {
                 let sugg = match sess.codemap().span_to_snippet(span) {
+                    Ok(ref s) if is_global => format!("dyn ({})", s),
                     Ok(s) => format!("dyn {}", s),
                     Err(_) => format!("dyn <type>")
                 };

From db6a5ee1aa57ec5f1d41b8a2a8519b7ee7d3598f Mon Sep 17 00:00:00 2001
From: Alexander Ronald Altman <alexanderaltman@me.com>
Date: Tue, 27 Feb 2018 23:57:47 -0600
Subject: [PATCH 13/14] Minor grammatical/style fix in docs.

---
 src/libcore/iter/iterator.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs
index 9d8a71250f88a..b06534c9c1ec9 100644
--- a/src/libcore/iter/iterator.rs
+++ b/src/libcore/iter/iterator.rs
@@ -1062,8 +1062,8 @@ pub trait Iterator {
     /// assert_eq!(merged, "alphabetagamma");
     /// ```
     ///
-    /// You can also rewrite this in terms of [`flat_map()`] which is preferable
-    /// in this case since that conveys intent clearer:
+    /// You can also rewrite this in terms of [`flat_map()`], which is preferable
+    /// in this case since it conveys intent more clearly:
     ///
     /// ```
     /// let words = ["alpha", "beta", "gamma"];

From b9e9b4a1461e3a49b68db56413324dc1b6a2ed60 Mon Sep 17 00:00:00 2001
From: Tobias Stolzmann <tobias.stolzmann@gmail.com>
Date: Wed, 28 Feb 2018 15:29:16 +0100
Subject: [PATCH 14/14] Add std::path::Path::ancestors

Squashed commit of the following:

commit 1b5d55e26f667b1a25c83c5db0cbb072013a5122
Author: Tobias Stolzmann <tobias.stolzmann@gmail.com>
Date:   Wed Feb 28 00:06:15 2018 +0100

    Bugfix

commit 4265c2db0b0aaa66fdeace5d329665fd2d13903a
Author: Tobias Stolzmann <tobias.stolzmann@gmail.com>
Date:   Tue Feb 27 22:59:12 2018 +0100

    Rename std::path::Path::parents into std::path::Path::ancestors

commit 2548e4b14d377d20adad0f08304a0dd6f8e48e23
Author: Tobias Stolzmann <tobias.stolzmann@gmail.com>
Date:   Tue Feb 27 12:50:37 2018 +0100

    Add tracking issue

commit 3e2ce51a6eea0e39af05849f76dd2cefd5035e86
Author: Tobias Stolzmann <tobias.stolzmann@gmail.com>
Date:   Mon Feb 26 15:05:15 2018 +0100

    impl FusedIterator for Parents

commit a7e096420809740311e19d963d4aba6df77be2f9
Author: Tobias Stolzmann <tobias.stolzmann@gmail.com>
Date:   Mon Feb 26 14:38:41 2018 +0100

    Clarify that the iterator returned will yield at least one value

commit 796a36ea203cd197cc4c810eebd21c7e3433e6f1
Author: Tobias Stolzmann <tobias.stolzmann@gmail.com>
Date:   Thu Feb 22 14:01:21 2018 +0100

    Fix examples

commit e279383b21f11c97269cb355a5b2a0ecdb65bb0c
Author: Tobias Stolzmann <tobias.stolzmann@gmail.com>
Date:   Thu Feb 22 04:47:24 2018 +0100

    Add std::path::Path::parents
---
 src/libstd/path.rs | 75 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 75 insertions(+)

diff --git a/src/libstd/path.rs b/src/libstd/path.rs
index 4bbad30a5a315..1608a752a463f 100644
--- a/src/libstd/path.rs
+++ b/src/libstd/path.rs
@@ -1035,6 +1035,50 @@ impl<'a> cmp::Ord for Components<'a> {
     }
 }
 
+/// An iterator over [`Path`] and its ancestors.
+///
+/// This `struct` is created by the [`ancestors`] method on [`Path`].
+/// See its documentation for more.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(path_ancestors)]
+///
+/// use std::path::Path;
+///
+/// let path = Path::new("/foo/bar");
+///
+/// for ancestor in path.ancestors() {
+///     println!("{}", ancestor.display());
+/// }
+/// ```
+///
+/// [`ancestors`]: struct.Path.html#method.ancestors
+/// [`Path`]: struct.Path.html
+#[derive(Copy, Clone, Debug)]
+#[unstable(feature = "path_ancestors", issue = "48581")]
+pub struct Ancestors<'a> {
+    next: Option<&'a Path>,
+}
+
+#[unstable(feature = "path_ancestors", issue = "48581")]
+impl<'a> Iterator for Ancestors<'a> {
+    type Item = &'a Path;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let next = self.next;
+        self.next = match next {
+            Some(path) => path.parent(),
+            None => None,
+        };
+        next
+    }
+}
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a> FusedIterator for Ancestors<'a> {}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Basic types and traits
 ////////////////////////////////////////////////////////////////////////////////
@@ -1820,6 +1864,37 @@ impl Path {
         })
     }
 
+    /// Produces an iterator over `Path` and its ancestors.
+    ///
+    /// The iterator will yield the `Path` that is returned if the [`parent`] method is used zero
+    /// or more times. That means, the iterator will yield `&self`, `&self.parent().unwrap()`,
+    /// `&self.parent().unwrap().parent().unwrap()` and so on. If the [`parent`] method returns
+    /// [`None`], the iterator will do likewise. The iterator will always yield at least one value,
+    /// namely `&self`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(path_ancestors)]
+    ///
+    /// use std::path::Path;
+    ///
+    /// let mut ancestors = Path::new("/foo/bar").ancestors();
+    /// assert_eq!(ancestors.next(), Some(Path::new("/foo/bar")));
+    /// assert_eq!(ancestors.next(), Some(Path::new("/foo")));
+    /// assert_eq!(ancestors.next(), Some(Path::new("/")));
+    /// assert_eq!(ancestors.next(), None);
+    /// ```
+    ///
+    /// [`None`]: ../../std/option/enum.Option.html#variant.None
+    /// [`parent`]: struct.Path.html#method.parent
+    #[unstable(feature = "path_ancestors", issue = "48581")]
+    pub fn ancestors(&self) -> Ancestors {
+        Ancestors {
+            next: Some(&self),
+        }
+    }
+
     /// Returns the final component of the `Path`, if there is one.
     ///
     /// If the path is a normal file, this is the file name. If it's the path of a directory, this