diff --git a/src/librustc/util/fs.rs b/src/librustc/util/fs.rs
index c290d8f893e9e..3b4b3998c5745 100644
--- a/src/librustc/util/fs.rs
+++ b/src/librustc/util/fs.rs
@@ -31,7 +31,7 @@ use std::io;
 //   https://github.com/rust-lang/rust/issues/25505#issuecomment-102876737
 pub fn fix_windows_verbatim_for_gcc(p: &Path) -> PathBuf {
     if !cfg!(windows) {
-        return p.to_path_buf()
+        return p.to_path_buf();
     }
     let mut components = p.components();
     let prefix = match components.next() {
@@ -58,7 +58,7 @@ pub fn fix_windows_verbatim_for_gcc(p: &Path) -> PathBuf {
 
 pub enum LinkOrCopy {
     Link,
-    Copy
+    Copy,
 }
 
 /// Copy `p` into `q`, preferring to use hard-linking if possible. If
@@ -76,7 +76,35 @@ pub fn link_or_copy<P: AsRef<Path>, Q: AsRef<Path>>(p: P, q: Q) -> io::Result<Li
         Err(_) => {
             match fs::copy(p, q) {
                 Ok(_) => Ok(LinkOrCopy::Copy),
-                Err(e) => Err(e)
+                Err(e) => Err(e),
+            }
+        }
+    }
+}
+
+#[derive(Debug)]
+pub enum RenameOrCopyRemove {
+    Rename,
+    CopyRemove,
+}
+
+/// Rename `p` into `q`, preferring to use `rename` if possible.
+/// If `rename` fails (rename may fail for reasons such as crossing
+/// filesystem), fallback to copy & remove
+pub fn rename_or_copy_remove<P: AsRef<Path>, Q: AsRef<Path>>(p: P,
+                                                             q: Q)
+                                                             -> io::Result<RenameOrCopyRemove> {
+    let p = p.as_ref();
+    let q = q.as_ref();
+    match fs::rename(p, q) {
+        Ok(()) => Ok(RenameOrCopyRemove::Rename),
+        Err(_) => {
+            match fs::copy(p, q) {
+                Ok(_) => {
+                    fs::remove_file(p)?;
+                    Ok(RenameOrCopyRemove::CopyRemove)
+                }
+                Err(e) => Err(e),
             }
         }
     }
@@ -93,8 +121,7 @@ pub fn create_dir_racy(path: &Path) -> io::Result<()> {
     }
     match path.parent() {
         Some(p) => try!(create_dir_racy(p)),
-        None => return Err(io::Error::new(io::ErrorKind::Other,
-                                          "failed to create whole tree")),
+        None => return Err(io::Error::new(io::ErrorKind::Other, "failed to create whole tree")),
     }
     match fs::create_dir(path) {
         Ok(()) => Ok(()),
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index a04a5b106b8f1..33bf4d5276adf 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -22,6 +22,7 @@ use rustc::middle::privacy::AccessLevels;
 use rustc::ty::{self, TyCtxt, Resolutions, GlobalArenas};
 use rustc::util::common::time;
 use rustc::util::nodemap::{NodeSet, NodeMap};
+use rustc::util::fs::rename_or_copy_remove;
 use rustc_borrowck as borrowck;
 use rustc_incremental::{self, IncrementalHashesMap};
 use rustc_incremental::ich::Fingerprint;
@@ -1084,10 +1085,9 @@ pub fn phase_5_run_llvm_passes(sess: &Session,
         // are going to build an executable
         if sess.opts.output_types.contains_key(&OutputType::Exe) {
             let f = outputs.path(OutputType::Object);
-            fs::copy(&f,
+            rename_or_copy_remove(&f,
                      f.with_file_name(format!("{}.0.o",
                                               f.file_stem().unwrap().to_string_lossy()))).unwrap();
-            fs::remove_file(f).unwrap();
         }
 
         // Remove assembly source, unless --save-temps was specified