about summary refs log tree commit diff
path: root/src/librustc_codegen_llvm
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustc_codegen_llvm')
-rw-r--r--src/librustc_codegen_llvm/abi.rs74
-rw-r--r--src/librustc_codegen_llvm/attributes.rs4
-rw-r--r--src/librustc_codegen_llvm/back/archive.rs57
-rw-r--r--src/librustc_codegen_llvm/back/bytecode.rs18
-rw-r--r--src/librustc_codegen_llvm/back/command.rs175
-rw-r--r--src/librustc_codegen_llvm/back/link.rs61
-rw-r--r--src/librustc_codegen_llvm/back/linker.rs1095
-rw-r--r--src/librustc_codegen_llvm/back/lto.rs72
-rw-r--r--src/librustc_codegen_llvm/back/rpath.rs15
-rw-r--r--src/librustc_codegen_llvm/back/symbol_export.rs395
-rw-r--r--src/librustc_codegen_llvm/back/wasm.rs4
-rw-r--r--src/librustc_codegen_llvm/back/write.rs176
-rw-r--r--src/librustc_codegen_llvm/base.rs278
-rw-r--r--src/librustc_codegen_llvm/builder.rs92
-rw-r--r--src/librustc_codegen_llvm/callee.rs26
-rw-r--r--src/librustc_codegen_llvm/common.rs51
-rw-r--r--src/librustc_codegen_llvm/context.rs58
-rw-r--r--src/librustc_codegen_llvm/debuginfo/metadata.rs538
-rw-r--r--src/librustc_codegen_llvm/debuginfo/mod.rs8
-rw-r--r--src/librustc_codegen_llvm/debuginfo/type_names.rs1
-rw-r--r--src/librustc_codegen_llvm/declare.rs16
-rw-r--r--src/librustc_codegen_llvm/intrinsic.rs67
-rw-r--r--src/librustc_codegen_llvm/lib.rs34
-rw-r--r--src/librustc_codegen_llvm/llvm/archive_ro.rs2
-rw-r--r--src/librustc_codegen_llvm/llvm/diagnostic.rs2
-rw-r--r--src/librustc_codegen_llvm/llvm/ffi.rs71
-rw-r--r--src/librustc_codegen_llvm/llvm/mod.rs2
-rw-r--r--src/librustc_codegen_llvm/llvm_util.rs9
-rw-r--r--src/librustc_codegen_llvm/meth.rs4
-rw-r--r--src/librustc_codegen_llvm/mir/analyze.rs56
-rw-r--r--src/librustc_codegen_llvm/mir/block.rs50
-rw-r--r--src/librustc_codegen_llvm/mir/constant.rs25
-rw-r--r--src/librustc_codegen_llvm/mir/mod.rs3
-rw-r--r--src/librustc_codegen_llvm/mir/operand.rs22
-rw-r--r--src/librustc_codegen_llvm/mir/place.rs24
-rw-r--r--src/librustc_codegen_llvm/mir/statement.rs18
-rw-r--r--src/librustc_codegen_llvm/mono_item.rs6
-rw-r--r--src/librustc_codegen_llvm/type_.rs2
-rw-r--r--src/librustc_codegen_llvm/type_of.rs4
39 files changed, 1069 insertions, 2546 deletions
diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs
index 7b93d3e795e..03b0b04d401 100644
--- a/src/librustc_codegen_llvm/abi.rs
+++ b/src/librustc_codegen_llvm/abi.rs
@@ -11,7 +11,7 @@
 use llvm::{self, AttributePlace};
 use base;
 use builder::{Builder, MemFlags};
-use common::{ty_fn_sig, C_usize};
+use common::C_usize;
 use context::CodegenCx;
 use mir::place::PlaceRef;
 use mir::operand::OperandValue;
@@ -19,7 +19,7 @@ use type_::Type;
 use type_of::{LayoutLlvmExt, PointerKind};
 use value::Value;
 
-use rustc_target::abi::{LayoutOf, Size, TyLayout};
+use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TyLayout, Abi as LayoutAbi};
 use rustc::ty::{self, Ty};
 use rustc::ty::layout;
 
@@ -225,9 +225,10 @@ impl ArgTypeExt<'ll, 'tcx> for ArgType<'tcx, Ty<'tcx>> {
                 // ...and then memcpy it to the intended destination.
                 base::call_memcpy(bx,
                                   bx.pointercast(dst.llval, Type::i8p(cx)),
+                                  self.layout.align,
                                   bx.pointercast(llscratch, Type::i8p(cx)),
+                                  scratch_align,
                                   C_usize(cx, self.layout.size.bytes()),
-                                  self.layout.align.min(scratch_align),
                                   MemFlags::empty());
 
                 bx.lifetime_end(llscratch, scratch_size);
@@ -276,6 +277,7 @@ pub trait FnTypeExt<'tcx> {
                       cx: &CodegenCx<'ll, 'tcx>,
                       abi: Abi);
     fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
+    fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
     fn llvm_cconv(&self) -> llvm::CallConv;
     fn apply_attrs_llfn(&self, llfn: &'ll Value);
     fn apply_attrs_callsite(&self, bx: &Builder<'a, 'll, 'tcx>, callsite: &'ll Value);
@@ -283,8 +285,7 @@ pub trait FnTypeExt<'tcx> {
 
 impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
     fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self {
-        let fn_ty = instance.ty(cx.tcx);
-        let sig = ty_fn_sig(cx, fn_ty);
+        let sig = instance.fn_sig(cx.tcx);
         let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
         FnType::new(cx, sig, &[])
     }
@@ -303,21 +304,49 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
         FnType::new_internal(cx, sig, extra_args, |ty, arg_idx| {
             let mut layout = cx.layout_of(ty);
             // Don't pass the vtable, it's not an argument of the virtual fn.
-            // Instead, pass just the (thin pointer) first field of `*dyn Trait`.
+            // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
+            // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
             if arg_idx == Some(0) {
-                if layout.is_unsized() {
-                    unimplemented!("by-value trait object is not \
-                                    yet implemented in #![feature(unsized_locals)]");
-                }
-                // FIXME(eddyb) `layout.field(cx, 0)` is not enough because e.g.
-                // `Box<dyn Trait>` has a few newtype wrappers around the raw
-                // pointer, so we'd have to "dig down" to find `*dyn Trait`.
-                let pointee = layout.ty.builtin_deref(true)
-                    .unwrap_or_else(|| {
-                        bug!("FnType::new_vtable: non-pointer self {:?}", layout)
-                    }).ty;
-                let fat_ptr_ty = cx.tcx.mk_mut_ptr(pointee);
-                layout = cx.layout_of(fat_ptr_ty).field(cx, 0);
+                let fat_pointer_ty = if layout.is_unsized() {
+                    // unsized `self` is passed as a pointer to `self`
+                    // FIXME (mikeyhew) change this to use &own if it is ever added to the language
+                    cx.tcx.mk_mut_ptr(layout.ty)
+                } else {
+                    match layout.abi {
+                        LayoutAbi::ScalarPair(..) => (),
+                        _ => bug!("receiver type has unsupported layout: {:?}", layout)
+                    }
+
+                    // In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self>
+                    // with a Scalar (not ScalarPair) ABI. This is a hack that is understood
+                    // elsewhere in the compiler as a method on a `dyn Trait`.
+                    // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
+                    // get a built-in pointer type
+                    let mut fat_pointer_layout = layout;
+                    'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
+                        && !fat_pointer_layout.ty.is_region_ptr()
+                    {
+                        'iter_fields: for i in 0..fat_pointer_layout.fields.count() {
+                            let field_layout = fat_pointer_layout.field(cx, i);
+
+                            if !field_layout.is_zst() {
+                                fat_pointer_layout = field_layout;
+                                continue 'descend_newtypes
+                            }
+                        }
+
+                        bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout);
+                    }
+
+                    fat_pointer_layout.ty
+                };
+
+                // we now have a type like `*mut RcBox<dyn Trait>`
+                // change its layout to that of `*mut ()`, a thin pointer, but keep the same type
+                // this is understood as a special case elsewhere in the compiler
+                let unit_pointer_ty = cx.tcx.mk_mut_ptr(cx.tcx.mk_unit());
+                layout = cx.layout_of(unit_pointer_ty);
+                layout.ty = fat_pointer_ty;
             }
             ArgType::new(layout)
         })
@@ -630,6 +659,13 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
         }
     }
 
+    fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
+        unsafe {
+            llvm::LLVMPointerType(self.llvm_type(cx),
+                                  cx.data_layout().instruction_address_space as c_uint)
+        }
+    }
+
     fn llvm_cconv(&self) -> llvm::CallConv {
         match self.conv {
             Conv::C => llvm::CCallConv,
diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs
index 90ba103ca4c..f45b3728bc1 100644
--- a/src/librustc_codegen_llvm/attributes.rs
+++ b/src/librustc_codegen_llvm/attributes.rs
@@ -154,7 +154,7 @@ pub fn from_fn_attrs(
     id: Option<DefId>,
 ) {
     let codegen_fn_attrs = id.map(|id| cx.tcx.codegen_fn_attrs(id))
-        .unwrap_or(CodegenFnAttrs::new());
+        .unwrap_or_else(|| CodegenFnAttrs::new());
 
     inline(cx, llfn, codegen_fn_attrs.inline);
 
@@ -297,7 +297,7 @@ pub fn provide_extern(providers: &mut Providers) {
             }
         ).collect::<FxHashMap<_, _>>();
 
-        let mut ret = FxHashMap();
+        let mut ret = FxHashMap::default();
         for lib in tcx.foreign_modules(cnum).iter() {
             let module = def_id_to_native_lib
                 .get(&lib.def_id)
diff --git a/src/librustc_codegen_llvm/back/archive.rs b/src/librustc_codegen_llvm/back/archive.rs
index af9efc6d7c4..54245a36017 100644
--- a/src/librustc_codegen_llvm/back/archive.rs
+++ b/src/librustc_codegen_llvm/back/archive.rs
@@ -52,28 +52,6 @@ enum Addition {
     },
 }
 
-pub fn find_library(name: &str, search_paths: &[PathBuf], sess: &Session)
-                    -> PathBuf {
-    // On Windows, static libraries sometimes show up as libfoo.a and other
-    // times show up as foo.lib
-    let oslibname = format!("{}{}{}",
-                            sess.target.target.options.staticlib_prefix,
-                            name,
-                            sess.target.target.options.staticlib_suffix);
-    let unixlibname = format!("lib{}.a", name);
-
-    for path in search_paths {
-        debug!("looking for {} inside {:?}", name, path);
-        let test = path.join(&oslibname);
-        if test.exists() { return test }
-        if oslibname != unixlibname {
-            let test = path.join(&unixlibname);
-            if test.exists() { return test }
-        }
-    }
-    sess.fatal(&format!("could not find native static library `{}`, \
-                         perhaps an -L flag is missing?", name));
-}
 
 fn is_relevant_child(c: &Child) -> bool {
     match c.name() {
@@ -105,15 +83,16 @@ impl<'a> ArchiveBuilder<'a> {
         if self.src_archive().is_none() {
             return Vec::new()
         }
+
         let archive = self.src_archive.as_ref().unwrap().as_ref().unwrap();
-        let ret = archive.iter()
-                         .filter_map(|child| child.ok())
-                         .filter(is_relevant_child)
-                         .filter_map(|child| child.name())
-                         .filter(|name| !self.removals.iter().any(|x| x == name))
-                         .map(|name| name.to_string())
-                         .collect();
-        return ret;
+
+        archive.iter()
+               .filter_map(|child| child.ok())
+               .filter(is_relevant_child)
+               .filter_map(|child| child.name())
+               .filter(|name| !self.removals.iter().any(|x| x == name))
+               .map(|name| name.to_owned())
+               .collect()
     }
 
     fn src_archive(&mut self) -> Option<&ArchiveRO> {
@@ -128,7 +107,7 @@ impl<'a> ArchiveBuilder<'a> {
     /// Adds all of the contents of a native library to this archive. This will
     /// search in the relevant locations for a library named `name`.
     pub fn add_native_library(&mut self, name: &str) {
-        let location = find_library(name, &self.config.lib_search_paths,
+        let location = ::rustc_codegen_utils::find_library(name, &self.config.lib_search_paths,
                                     self.config.sess);
         self.add_archive(&location, |_| false).unwrap_or_else(|e| {
             self.config.sess.fatal(&format!("failed to add native library {}: {}",
@@ -193,7 +172,7 @@ impl<'a> ArchiveBuilder<'a> {
         let name = file.file_name().unwrap().to_str().unwrap();
         self.additions.push(Addition::File {
             path: file.to_path_buf(),
-            name_in_archive: name.to_string(),
+            name_in_archive: name.to_owned(),
         });
     }
 
@@ -206,13 +185,8 @@ impl<'a> ArchiveBuilder<'a> {
     /// Combine the provided files, rlibs, and native libraries into a single
     /// `Archive`.
     pub fn build(&mut self) {
-        let kind = match self.llvm_archive_kind() {
-            Ok(kind) => kind,
-            Err(kind) => {
-                self.config.sess.fatal(&format!("Don't know how to build archive of type: {}",
-                                                kind));
-            }
-        };
+        let kind = self.llvm_archive_kind().unwrap_or_else(|kind|
+            self.config.sess.fatal(&format!("Don't know how to build archive of type: {}", kind)));
 
         if let Err(e) = self.build_with_llvm(kind) {
             self.config.sess.fatal(&format!("failed to build archive: {}", e));
@@ -303,10 +277,9 @@ impl<'a> ArchiveBuilder<'a> {
             let ret = if r.into_result().is_err() {
                 let err = llvm::LLVMRustGetLastError();
                 let msg = if err.is_null() {
-                    "failed to write archive".to_string()
+                    "failed to write archive".into()
                 } else {
                     String::from_utf8_lossy(CStr::from_ptr(err).to_bytes())
-                            .into_owned()
                 };
                 Err(io::Error::new(io::ErrorKind::Other, msg))
             } else {
@@ -315,7 +288,7 @@ impl<'a> ArchiveBuilder<'a> {
             for member in members {
                 llvm::LLVMRustArchiveMemberFree(member);
             }
-            return ret
+            ret
         }
     }
 }
diff --git a/src/librustc_codegen_llvm/back/bytecode.rs b/src/librustc_codegen_llvm/back/bytecode.rs
index 9a3dd9d2f88..0b264de18c1 100644
--- a/src/librustc_codegen_llvm/back/bytecode.rs
+++ b/src/librustc_codegen_llvm/back/bytecode.rs
@@ -42,7 +42,7 @@ use flate2::write::DeflateEncoder;
 
 // This is the "magic number" expected at the beginning of a LLVM bytecode
 // object in an rlib.
-pub const RLIB_BYTECODE_OBJECT_MAGIC: &'static [u8] = b"RUST_OBJECT";
+pub const RLIB_BYTECODE_OBJECT_MAGIC: &[u8] = b"RUST_OBJECT";
 
 // The version number this compiler will write to bytecode objects in rlibs
 pub const RLIB_BYTECODE_OBJECT_VERSION: u8 = 2;
@@ -106,39 +106,39 @@ pub struct DecodedBytecode<'a> {
 }
 
 impl<'a> DecodedBytecode<'a> {
-    pub fn new(data: &'a [u8]) -> Result<DecodedBytecode<'a>, String> {
+    pub fn new(data: &'a [u8]) -> Result<DecodedBytecode<'a>, &'static str> {
         if !data.starts_with(RLIB_BYTECODE_OBJECT_MAGIC) {
-            return Err("magic bytecode prefix not found".to_string())
+            return Err("magic bytecode prefix not found")
         }
         let data = &data[RLIB_BYTECODE_OBJECT_MAGIC.len()..];
         if !data.starts_with(&[RLIB_BYTECODE_OBJECT_VERSION, 0, 0, 0]) {
-            return Err("wrong version prefix found in bytecode".to_string())
+            return Err("wrong version prefix found in bytecode")
         }
         let data = &data[4..];
         if data.len() < 4 {
-            return Err("bytecode corrupted".to_string())
+            return Err("bytecode corrupted")
         }
         let identifier_len = unsafe {
             u32::from_le(ptr::read_unaligned(data.as_ptr() as *const u32)) as usize
         };
         let data = &data[4..];
         if data.len() < identifier_len {
-            return Err("bytecode corrupted".to_string())
+            return Err("bytecode corrupted")
         }
         let identifier = match str::from_utf8(&data[..identifier_len]) {
             Ok(s) => s,
-            Err(_) => return Err("bytecode corrupted".to_string())
+            Err(_) => return Err("bytecode corrupted")
         };
         let data = &data[identifier_len..];
         if data.len() < 8 {
-            return Err("bytecode corrupted".to_string())
+            return Err("bytecode corrupted")
         }
         let bytecode_len = unsafe {
             u64::from_le(ptr::read_unaligned(data.as_ptr() as *const u64)) as usize
         };
         let data = &data[8..];
         if data.len() < bytecode_len {
-            return Err("bytecode corrupted".to_string())
+            return Err("bytecode corrupted")
         }
         let encoded_bytecode = &data[..bytecode_len];
 
diff --git a/src/librustc_codegen_llvm/back/command.rs b/src/librustc_codegen_llvm/back/command.rs
deleted file mode 100644
index 9ebbdd7c3c9..00000000000
--- a/src/librustc_codegen_llvm/back/command.rs
+++ /dev/null
@@ -1,175 +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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! A thin wrapper around `Command` in the standard library which allows us to
-//! read the arguments that are built up.
-
-use std::ffi::{OsStr, OsString};
-use std::fmt;
-use std::io;
-use std::mem;
-use std::process::{self, Output};
-
-use rustc_target::spec::LldFlavor;
-
-#[derive(Clone)]
-pub struct Command {
-    program: Program,
-    args: Vec<OsString>,
-    env: Vec<(OsString, OsString)>,
-}
-
-#[derive(Clone)]
-enum Program {
-    Normal(OsString),
-    CmdBatScript(OsString),
-    Lld(OsString, LldFlavor)
-}
-
-impl Command {
-    pub fn new<P: AsRef<OsStr>>(program: P) -> Command {
-        Command::_new(Program::Normal(program.as_ref().to_owned()))
-    }
-
-    pub fn bat_script<P: AsRef<OsStr>>(program: P) -> Command {
-        Command::_new(Program::CmdBatScript(program.as_ref().to_owned()))
-    }
-
-    pub fn lld<P: AsRef<OsStr>>(program: P, flavor: LldFlavor) -> Command {
-        Command::_new(Program::Lld(program.as_ref().to_owned(), flavor))
-    }
-
-    fn _new(program: Program) -> Command {
-        Command {
-            program,
-            args: Vec::new(),
-            env: Vec::new(),
-        }
-    }
-
-    pub fn arg<P: AsRef<OsStr>>(&mut self, arg: P) -> &mut Command {
-        self._arg(arg.as_ref());
-        self
-    }
-
-    pub fn args<I>(&mut self, args: I) -> &mut Command
-        where I: IntoIterator,
-              I::Item: AsRef<OsStr>,
-    {
-        for arg in args {
-            self._arg(arg.as_ref());
-        }
-        self
-    }
-
-    fn _arg(&mut self, arg: &OsStr) {
-        self.args.push(arg.to_owned());
-    }
-
-    pub fn env<K, V>(&mut self, key: K, value: V) -> &mut Command
-        where K: AsRef<OsStr>,
-              V: AsRef<OsStr>
-    {
-        self._env(key.as_ref(), value.as_ref());
-        self
-    }
-
-    fn _env(&mut self, key: &OsStr, value: &OsStr) {
-        self.env.push((key.to_owned(), value.to_owned()));
-    }
-
-    pub fn output(&mut self) -> io::Result<Output> {
-        self.command().output()
-    }
-
-    pub fn command(&self) -> process::Command {
-        let mut ret = match self.program {
-            Program::Normal(ref p) => process::Command::new(p),
-            Program::CmdBatScript(ref p) => {
-                let mut c = process::Command::new("cmd");
-                c.arg("/c").arg(p);
-                c
-            }
-            Program::Lld(ref p, flavor) => {
-                let mut c = process::Command::new(p);
-                c.arg("-flavor").arg(match flavor {
-                    LldFlavor::Wasm => "wasm",
-                    LldFlavor::Ld => "gnu",
-                    LldFlavor::Link => "link",
-                    LldFlavor::Ld64 => "darwin",
-                });
-                c
-            }
-        };
-        ret.args(&self.args);
-        ret.envs(self.env.clone());
-        return ret
-    }
-
-    // extensions
-
-    pub fn get_args(&self) -> &[OsString] {
-        &self.args
-    }
-
-    pub fn take_args(&mut self) -> Vec<OsString> {
-        mem::replace(&mut self.args, Vec::new())
-    }
-
-    /// Returns a `true` if we're pretty sure that this'll blow OS spawn limits,
-    /// or `false` if we should attempt to spawn and see what the OS says.
-    pub fn very_likely_to_exceed_some_spawn_limit(&self) -> bool {
-        // We mostly only care about Windows in this method, on Unix the limits
-        // can be gargantuan anyway so we're pretty unlikely to hit them
-        if cfg!(unix) {
-            return false
-        }
-
-        // Right now LLD doesn't support the `@` syntax of passing an argument
-        // through files, so regardless of the platform we try to go to the OS
-        // on this one.
-        if let Program::Lld(..) = self.program {
-            return false
-        }
-
-        // Ok so on Windows to spawn a process is 32,768 characters in its
-        // command line [1]. Unfortunately we don't actually have access to that
-        // as it's calculated just before spawning. Instead we perform a
-        // poor-man's guess as to how long our command line will be. We're
-        // assuming here that we don't have to escape every character...
-        //
-        // Turns out though that `cmd.exe` has even smaller limits, 8192
-        // characters [2]. Linkers can often be batch scripts (for example
-        // Emscripten, Gecko's current build system) which means that we're
-        // running through batch scripts. These linkers often just forward
-        // arguments elsewhere (and maybe tack on more), so if we blow 8192
-        // bytes we'll typically cause them to blow as well.
-        //
-        // Basically as a result just perform an inflated estimate of what our
-        // command line will look like and test if it's > 8192 (we actually
-        // test against 6k to artificially inflate our estimate). If all else
-        // fails we'll fall back to the normal unix logic of testing the OS
-        // error code if we fail to spawn and automatically re-spawning the
-        // linker with smaller arguments.
-        //
-        // [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx
-        // [2]: https://blogs.msdn.microsoft.com/oldnewthing/20031210-00/?p=41553
-
-        let estimated_command_line_len =
-            self.args.iter().map(|a| a.len()).sum::<usize>();
-        estimated_command_line_len > 1024 * 6
-    }
-}
-
-impl fmt::Debug for Command {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        self.command().fmt(f)
-    }
-}
diff --git a/src/librustc_codegen_llvm/back/link.rs b/src/librustc_codegen_llvm/back/link.rs
index 9fac343b846..111637b6aa9 100644
--- a/src/librustc_codegen_llvm/back/link.rs
+++ b/src/librustc_codegen_llvm/back/link.rs
@@ -12,8 +12,6 @@ use back::wasm;
 use cc::windows_registry;
 use super::archive::{ArchiveBuilder, ArchiveConfig};
 use super::bytecode::RLIB_BYTECODE_EXTENSION;
-use super::linker::Linker;
-use super::command::Command;
 use super::rpath::RPathConfig;
 use super::rpath;
 use metadata::METADATA_FILENAME;
@@ -31,6 +29,8 @@ use rustc::hir::def_id::CrateNum;
 use tempfile::{Builder as TempFileBuilder, TempDir};
 use rustc_target::spec::{PanicStrategy, RelroLevel, LinkerFlavor};
 use rustc_data_structures::fx::FxHashSet;
+use rustc_codegen_utils::linker::Linker;
+use rustc_codegen_utils::command::Command;
 use context::get_reloc_model;
 use llvm;
 
@@ -47,8 +47,8 @@ use std::str;
 use syntax::attr;
 
 pub use rustc_codegen_utils::link::{find_crate_name, filename_for_input, default_output_for_target,
-                                  invalid_output_for_target, out_filename, check_file_is_writeable,
-                                  filename_for_metadata};
+                                    invalid_output_for_target, filename_for_metadata,
+                                    out_filename, check_file_is_writeable};
 
 // The third parameter is for env vars, used on windows to set up the
 // path for MSVC to find its DLLs, and gcc to find its bundled
@@ -107,13 +107,10 @@ pub fn get_linker(sess: &Session, linker: &Path, flavor: LinkerFlavor) -> (PathB
 }
 
 pub fn remove(sess: &Session, path: &Path) {
-    match fs::remove_file(path) {
-        Ok(..) => {}
-        Err(e) => {
-            sess.err(&format!("failed to remove {}: {}",
-                             path.display(),
-                             e));
-        }
+    if let Err(e) = fs::remove_file(path) {
+        sess.err(&format!("failed to remove {}: {}",
+                          path.display(),
+                          e));
     }
 }
 
@@ -147,9 +144,7 @@ pub(crate) fn link_binary(sess: &Session,
 
     // Remove the temporary object file and metadata if we aren't saving temps
     if !sess.opts.cg.save_temps {
-        if sess.opts.output_types.should_codegen() &&
-            !preserve_objects_for_their_debuginfo(sess)
-        {
+        if sess.opts.output_types.should_codegen() && !preserve_objects_for_their_debuginfo(sess) {
             for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
                 remove(sess, obj);
             }
@@ -186,7 +181,7 @@ fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool {
     // the objects as they're losslessly contained inside the archives.
     let output_linked = sess.crate_types.borrow()
         .iter()
-        .any(|x| *x != config::CrateType::Rlib && *x != config::CrateType::Staticlib);
+        .any(|&x| x != config::CrateType::Rlib && x != config::CrateType::Staticlib);
     if !output_linked {
         return false
     }
@@ -270,7 +265,7 @@ pub(crate) fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum)
     // crates providing these functions don't participate in LTO (e.g.
     // no_builtins or compiler builtins crates).
     !sess.target.target.options.no_builtins &&
-        (info.is_no_builtins.contains(&cnum) || info.compiler_builtins == Some(cnum))
+        (info.compiler_builtins == Some(cnum) || info.is_no_builtins.contains(&cnum))
 }
 
 fn link_binary_output(sess: &Session,
@@ -291,13 +286,10 @@ fn link_binary_output(sess: &Session,
         // final destination, with a `fs::rename` call. In order for the rename to
         // always succeed, the temporary file needs to be on the same filesystem,
         // which is why we create it inside the output directory specifically.
-        let metadata_tmpdir = match TempFileBuilder::new()
+        let metadata_tmpdir = TempFileBuilder::new()
             .prefix("rmeta")
             .tempdir_in(out_filename.parent().unwrap())
-        {
-            Ok(tmpdir) => tmpdir,
-            Err(err) => sess.fatal(&format!("couldn't create a temp dir: {}", err)),
-        };
+            .unwrap_or_else(|err| sess.fatal(&format!("couldn't create a temp dir: {}", err)));
         let metadata = emit_metadata(sess, codegen_results, &metadata_tmpdir);
         if let Err(e) = fs::rename(metadata, &out_filename) {
             sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
@@ -305,10 +297,8 @@ fn link_binary_output(sess: &Session,
         out_filenames.push(out_filename);
     }
 
-    let tmpdir = match TempFileBuilder::new().prefix("rustc").tempdir() {
-        Ok(tmpdir) => tmpdir,
-        Err(err) => sess.fatal(&format!("couldn't create a temp dir: {}", err)),
-    };
+    let tmpdir = TempFileBuilder::new().prefix("rustc").tempdir().unwrap_or_else(|err|
+        sess.fatal(&format!("couldn't create a temp dir: {}", err)));
 
     if outputs.outputs.should_codegen() {
         let out_filename = out_filename(sess, crate_type, outputs, crate_name);
@@ -342,7 +332,8 @@ fn archive_search_paths(sess: &Session) -> Vec<PathBuf> {
     sess.target_filesearch(PathKind::Native).for_each_lib_search_path(|path, _| {
         search.push(path.to_path_buf());
     });
-    return search;
+
+    search
 }
 
 fn archive_config<'a>(sess: &'a Session,
@@ -701,7 +692,8 @@ fn link_natively(sess: &Session,
     }
 
     {
-        let mut linker = codegen_results.linker_info.to_linker(cmd, &sess, flavor);
+        let target_cpu = ::llvm_util::target_cpu(sess);
+        let mut linker = codegen_results.linker_info.to_linker(cmd, &sess, flavor, target_cpu);
         link_args(&mut *linker, flavor, sess, crate_type, tmpdir,
                   out_filename, codegen_results);
         cmd = linker.finalize();
@@ -813,8 +805,8 @@ fn link_natively(sess: &Session,
                     .unwrap_or_else(|_| {
                         let mut x = "Non-UTF-8 output: ".to_string();
                         x.extend(s.iter()
-                                 .flat_map(|&b| ascii::escape_default(b))
-                                 .map(|b| char::from_u32(b as u32).unwrap()));
+                                  .flat_map(|&b| ascii::escape_default(b))
+                                  .map(char::from));
                         x
                     })
             }
@@ -869,9 +861,8 @@ fn link_natively(sess: &Session,
         sess.opts.debuginfo != DebugInfo::None &&
         !preserve_objects_for_their_debuginfo(sess)
     {
-        match Command::new("dsymutil").arg(out_filename).output() {
-            Ok(..) => {}
-            Err(e) => sess.fatal(&format!("failed to run dsymutil: {}", e)),
+        if let Err(e) = Command::new("dsymutil").arg(out_filename).output() {
+            sess.fatal(&format!("failed to run dsymutil: {}", e))
         }
     }
 
@@ -1011,8 +1002,7 @@ fn exec_linker(sess: &Session, cmd: &mut Command, out_filename: &Path, tmpdir: &
                 // ensure the line is interpreted as one whole argument.
                 for c in self.arg.chars() {
                     match c {
-                        '\\' |
-                        ' ' => write!(f, "\\{}", c)?,
+                        '\\' | ' ' => write!(f, "\\{}", c)?,
                         c => write!(f, "{}", c)?,
                     }
                 }
@@ -1313,7 +1303,7 @@ fn add_upstream_rust_crates(cmd: &mut dyn Linker,
     // for the current implementation of the standard library.
     let mut group_end = None;
     let mut group_start = None;
-    let mut end_with = FxHashSet();
+    let mut end_with = FxHashSet::default();
     let info = &codegen_results.crate_info;
     for &(cnum, _) in deps.iter().rev() {
         if let Some(missing) = info.missing_lang_items.get(&cnum) {
@@ -1425,7 +1415,6 @@ fn add_upstream_rust_crates(cmd: &mut dyn Linker,
         for f in archive.src_files() {
             if f.ends_with(RLIB_BYTECODE_EXTENSION) || f == METADATA_FILENAME {
                 archive.remove_file(&f);
-                continue
             }
         }
 
diff --git a/src/librustc_codegen_llvm/back/linker.rs b/src/librustc_codegen_llvm/back/linker.rs
deleted file mode 100644
index e18c8b9dec4..00000000000
--- a/src/librustc_codegen_llvm/back/linker.rs
+++ /dev/null
@@ -1,1095 +0,0 @@
-// Copyright 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use rustc_data_structures::fx::FxHashMap;
-use std::ffi::{OsStr, OsString};
-use std::fs::{self, File};
-use std::io::prelude::*;
-use std::io::{self, BufWriter};
-use std::path::{Path, PathBuf};
-
-use back::archive;
-use back::command::Command;
-use back::symbol_export;
-use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
-use rustc::middle::dependency_format::Linkage;
-use rustc::session::Session;
-use rustc::session::config::{self, CrateType, OptLevel, DebugInfo,
-                             CrossLangLto};
-use rustc::ty::TyCtxt;
-use rustc_target::spec::{LinkerFlavor, LldFlavor};
-use serialize::{json, Encoder};
-use llvm_util;
-
-/// For all the linkers we support, and information they might
-/// need out of the shared crate context before we get rid of it.
-pub struct LinkerInfo {
-    exports: FxHashMap<CrateType, Vec<String>>,
-}
-
-impl LinkerInfo {
-    pub fn new(tcx: TyCtxt) -> LinkerInfo {
-        LinkerInfo {
-            exports: tcx.sess.crate_types.borrow().iter().map(|&c| {
-                (c, exported_symbols(tcx, c))
-            }).collect(),
-        }
-    }
-
-    pub fn to_linker<'a>(&'a self,
-                         cmd: Command,
-                         sess: &'a Session,
-                         flavor: LinkerFlavor) -> Box<dyn Linker+'a> {
-        match flavor {
-            LinkerFlavor::Lld(LldFlavor::Link) |
-            LinkerFlavor::Msvc => {
-                Box::new(MsvcLinker {
-                    cmd,
-                    sess,
-                    info: self
-                }) as Box<dyn Linker>
-            }
-            LinkerFlavor::Em =>  {
-                Box::new(EmLinker {
-                    cmd,
-                    sess,
-                    info: self
-                }) as Box<dyn Linker>
-            }
-            LinkerFlavor::Gcc =>  {
-                Box::new(GccLinker {
-                    cmd,
-                    sess,
-                    info: self,
-                    hinted_static: false,
-                    is_ld: false,
-                }) as Box<dyn Linker>
-            }
-
-            LinkerFlavor::Lld(LldFlavor::Ld) |
-            LinkerFlavor::Lld(LldFlavor::Ld64) |
-            LinkerFlavor::Ld => {
-                Box::new(GccLinker {
-                    cmd,
-                    sess,
-                    info: self,
-                    hinted_static: false,
-                    is_ld: true,
-                }) as Box<dyn Linker>
-            }
-
-            LinkerFlavor::Lld(LldFlavor::Wasm) => {
-                Box::new(WasmLd {
-                    cmd,
-                    sess,
-                    info: self
-                }) as Box<dyn Linker>
-            }
-        }
-    }
-}
-
-/// Linker abstraction used by back::link to build up the command to invoke a
-/// linker.
-///
-/// This trait is the total list of requirements needed by `back::link` and
-/// represents the meaning of each option being passed down. This trait is then
-/// used to dispatch on whether a GNU-like linker (generally `ld.exe`) or an
-/// MSVC linker (e.g. `link.exe`) is being used.
-pub trait Linker {
-    fn link_dylib(&mut self, lib: &str);
-    fn link_rust_dylib(&mut self, lib: &str, path: &Path);
-    fn link_framework(&mut self, framework: &str);
-    fn link_staticlib(&mut self, lib: &str);
-    fn link_rlib(&mut self, lib: &Path);
-    fn link_whole_rlib(&mut self, lib: &Path);
-    fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]);
-    fn include_path(&mut self, path: &Path);
-    fn framework_path(&mut self, path: &Path);
-    fn output_filename(&mut self, path: &Path);
-    fn add_object(&mut self, path: &Path);
-    fn gc_sections(&mut self, keep_metadata: bool);
-    fn position_independent_executable(&mut self);
-    fn no_position_independent_executable(&mut self);
-    fn full_relro(&mut self);
-    fn partial_relro(&mut self);
-    fn no_relro(&mut self);
-    fn optimize(&mut self);
-    fn pgo_gen(&mut self);
-    fn debuginfo(&mut self);
-    fn no_default_libraries(&mut self);
-    fn build_dylib(&mut self, out_filename: &Path);
-    fn build_static_executable(&mut self);
-    fn args(&mut self, args: &[String]);
-    fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType);
-    fn subsystem(&mut self, subsystem: &str);
-    fn group_start(&mut self);
-    fn group_end(&mut self);
-    fn cross_lang_lto(&mut self);
-    // Should have been finalize(self), but we don't support self-by-value on trait objects (yet?).
-    fn finalize(&mut self) -> Command;
-}
-
-pub struct GccLinker<'a> {
-    cmd: Command,
-    sess: &'a Session,
-    info: &'a LinkerInfo,
-    hinted_static: bool, // Keeps track of the current hinting mode.
-    // Link as ld
-    is_ld: bool,
-}
-
-impl<'a> GccLinker<'a> {
-    /// Argument that must be passed *directly* to the linker
-    ///
-    /// These arguments need to be prepended with '-Wl,' when a gcc-style linker is used
-    fn linker_arg<S>(&mut self, arg: S) -> &mut Self
-        where S: AsRef<OsStr>
-    {
-        if !self.is_ld {
-            let mut os = OsString::from("-Wl,");
-            os.push(arg.as_ref());
-            self.cmd.arg(os);
-        } else {
-            self.cmd.arg(arg);
-        }
-        self
-    }
-
-    fn takes_hints(&self) -> bool {
-        !self.sess.target.target.options.is_like_osx
-    }
-
-    // Some platforms take hints about whether a library is static or dynamic.
-    // For those that support this, we ensure we pass the option if the library
-    // was flagged "static" (most defaults are dynamic) to ensure that if
-    // libfoo.a and libfoo.so both exist that the right one is chosen.
-    fn hint_static(&mut self) {
-        if !self.takes_hints() { return }
-        if !self.hinted_static {
-            self.linker_arg("-Bstatic");
-            self.hinted_static = true;
-        }
-    }
-
-    fn hint_dynamic(&mut self) {
-        if !self.takes_hints() { return }
-        if self.hinted_static {
-            self.linker_arg("-Bdynamic");
-            self.hinted_static = false;
-        }
-    }
-
-    fn push_cross_lang_lto_args(&mut self, plugin_path: Option<&OsStr>) {
-        if let Some(plugin_path) = plugin_path {
-            let mut arg = OsString::from("-plugin=");
-            arg.push(plugin_path);
-            self.linker_arg(&arg);
-        }
-
-        let opt_level = match self.sess.opts.optimize {
-            config::OptLevel::No => "O0",
-            config::OptLevel::Less => "O1",
-            config::OptLevel::Default => "O2",
-            config::OptLevel::Aggressive => "O3",
-            config::OptLevel::Size => "Os",
-            config::OptLevel::SizeMin => "Oz",
-        };
-
-        self.linker_arg(&format!("-plugin-opt={}", opt_level));
-        self.linker_arg(&format!("-plugin-opt=mcpu={}", llvm_util::target_cpu(self.sess)));
-
-        match self.sess.lto() {
-            config::Lto::Thin |
-            config::Lto::ThinLocal => {
-                self.linker_arg("-plugin-opt=thin");
-            }
-            config::Lto::Fat |
-            config::Lto::No => {
-                // default to regular LTO
-            }
-        }
-    }
-}
-
-impl<'a> Linker for GccLinker<'a> {
-    fn link_dylib(&mut self, lib: &str) { self.hint_dynamic(); self.cmd.arg(format!("-l{}",lib)); }
-    fn link_staticlib(&mut self, lib: &str) {
-        self.hint_static(); self.cmd.arg(format!("-l{}",lib));
-    }
-    fn link_rlib(&mut self, lib: &Path) { self.hint_static(); self.cmd.arg(lib); }
-    fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); }
-    fn framework_path(&mut self, path: &Path) { self.cmd.arg("-F").arg(path); }
-    fn output_filename(&mut self, path: &Path) { self.cmd.arg("-o").arg(path); }
-    fn add_object(&mut self, path: &Path) { self.cmd.arg(path); }
-    fn position_independent_executable(&mut self) { self.cmd.arg("-pie"); }
-    fn no_position_independent_executable(&mut self) { self.cmd.arg("-no-pie"); }
-    fn full_relro(&mut self) { self.linker_arg("-zrelro"); self.linker_arg("-znow"); }
-    fn partial_relro(&mut self) { self.linker_arg("-zrelro"); }
-    fn no_relro(&mut self) { self.linker_arg("-znorelro"); }
-    fn build_static_executable(&mut self) { self.cmd.arg("-static"); }
-    fn args(&mut self, args: &[String]) { self.cmd.args(args); }
-
-    fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
-        self.hint_dynamic();
-        self.cmd.arg(format!("-l{}",lib));
-    }
-
-    fn link_framework(&mut self, framework: &str) {
-        self.hint_dynamic();
-        self.cmd.arg("-framework").arg(framework);
-    }
-
-    // Here we explicitly ask that the entire archive is included into the
-    // result artifact. For more details see #15460, but the gist is that
-    // the linker will strip away any unused objects in the archive if we
-    // don't otherwise explicitly reference them. This can occur for
-    // libraries which are just providing bindings, libraries with generic
-    // functions, etc.
-    fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]) {
-        self.hint_static();
-        let target = &self.sess.target.target;
-        if !target.options.is_like_osx {
-            self.linker_arg("--whole-archive").cmd.arg(format!("-l{}",lib));
-            self.linker_arg("--no-whole-archive");
-        } else {
-            // -force_load is the macOS equivalent of --whole-archive, but it
-            // involves passing the full path to the library to link.
-            self.linker_arg("-force_load");
-            let lib = archive::find_library(lib, search_path, &self.sess);
-            self.linker_arg(&lib);
-        }
-    }
-
-    fn link_whole_rlib(&mut self, lib: &Path) {
-        self.hint_static();
-        if self.sess.target.target.options.is_like_osx {
-            self.linker_arg("-force_load");
-            self.linker_arg(&lib);
-        } else {
-            self.linker_arg("--whole-archive").cmd.arg(lib);
-            self.linker_arg("--no-whole-archive");
-        }
-    }
-
-    fn gc_sections(&mut self, keep_metadata: bool) {
-        // The dead_strip option to the linker specifies that functions and data
-        // unreachable by the entry point will be removed. This is quite useful
-        // with Rust's compilation model of compiling libraries at a time into
-        // one object file. For example, this brings hello world from 1.7MB to
-        // 458K.
-        //
-        // Note that this is done for both executables and dynamic libraries. We
-        // won't get much benefit from dylibs because LLVM will have already
-        // stripped away as much as it could. This has not been seen to impact
-        // link times negatively.
-        //
-        // -dead_strip can't be part of the pre_link_args because it's also used
-        // for partial linking when using multiple codegen units (-r).  So we
-        // insert it here.
-        if self.sess.target.target.options.is_like_osx {
-            self.linker_arg("-dead_strip");
-        } else if self.sess.target.target.options.is_like_solaris {
-            self.linker_arg("-zignore");
-
-        // If we're building a dylib, we don't use --gc-sections because LLVM
-        // has already done the best it can do, and we also don't want to
-        // eliminate the metadata. If we're building an executable, however,
-        // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67%
-        // reduction.
-        } else if !keep_metadata {
-            self.linker_arg("--gc-sections");
-        }
-    }
-
-    fn optimize(&mut self) {
-        if !self.sess.target.target.options.linker_is_gnu { return }
-
-        // GNU-style linkers support optimization with -O. GNU ld doesn't
-        // need a numeric argument, but other linkers do.
-        if self.sess.opts.optimize == config::OptLevel::Default ||
-           self.sess.opts.optimize == config::OptLevel::Aggressive {
-            self.linker_arg("-O1");
-        }
-    }
-
-    fn pgo_gen(&mut self) {
-        if !self.sess.target.target.options.linker_is_gnu { return }
-
-        // If we're doing PGO generation stuff and on a GNU-like linker, use the
-        // "-u" flag to properly pull in the profiler runtime bits.
-        //
-        // This is because LLVM otherwise won't add the needed initialization
-        // for us on Linux (though the extra flag should be harmless if it
-        // does).
-        //
-        // See https://reviews.llvm.org/D14033 and https://reviews.llvm.org/D14030.
-        //
-        // Though it may be worth to try to revert those changes upstream, since
-        // the overhead of the initialization should be minor.
-        self.cmd.arg("-u");
-        self.cmd.arg("__llvm_profile_runtime");
-    }
-
-    fn debuginfo(&mut self) {
-        match self.sess.opts.debuginfo {
-            DebugInfo::None => {
-                // If we are building without debuginfo enabled and we were called with
-                // `-Zstrip-debuginfo-if-disabled=yes`, tell the linker to strip any debuginfo
-                // found when linking to get rid of symbols from libstd.
-                match self.sess.opts.debugging_opts.strip_debuginfo_if_disabled {
-                    Some(true) => { self.linker_arg("-S"); },
-                    _ => {},
-                }
-            },
-            _ => {},
-        };
-    }
-
-    fn no_default_libraries(&mut self) {
-        if !self.is_ld {
-            self.cmd.arg("-nodefaultlibs");
-        }
-    }
-
-    fn build_dylib(&mut self, out_filename: &Path) {
-        // On mac we need to tell the linker to let this library be rpathed
-        if self.sess.target.target.options.is_like_osx {
-            self.cmd.arg("-dynamiclib");
-            self.linker_arg("-dylib");
-
-            // Note that the `osx_rpath_install_name` option here is a hack
-            // purely to support rustbuild right now, we should get a more
-            // principled solution at some point to force the compiler to pass
-            // the right `-Wl,-install_name` with an `@rpath` in it.
-            if self.sess.opts.cg.rpath ||
-               self.sess.opts.debugging_opts.osx_rpath_install_name {
-                self.linker_arg("-install_name");
-                let mut v = OsString::from("@rpath/");
-                v.push(out_filename.file_name().unwrap());
-                self.linker_arg(&v);
-            }
-        } else {
-            self.cmd.arg("-shared");
-        }
-    }
-
-    fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
-        // If we're compiling a dylib, then we let symbol visibility in object
-        // files to take care of whether they're exported or not.
-        //
-        // If we're compiling a cdylib, however, we manually create a list of
-        // exported symbols to ensure we don't expose any more. The object files
-        // have far more public symbols than we actually want to export, so we
-        // hide them all here.
-        if crate_type == CrateType::Dylib ||
-           crate_type == CrateType::ProcMacro {
-            return
-        }
-
-        let mut arg = OsString::new();
-        let path = tmpdir.join("list");
-
-        debug!("EXPORTED SYMBOLS:");
-
-        if self.sess.target.target.options.is_like_osx {
-            // Write a plain, newline-separated list of symbols
-            let res = (|| -> io::Result<()> {
-                let mut f = BufWriter::new(File::create(&path)?);
-                for sym in self.info.exports[&crate_type].iter() {
-                    debug!("  _{}", sym);
-                    writeln!(f, "_{}", sym)?;
-                }
-                Ok(())
-            })();
-            if let Err(e) = res {
-                self.sess.fatal(&format!("failed to write lib.def file: {}", e));
-            }
-        } else {
-            // Write an LD version script
-            let res = (|| -> io::Result<()> {
-                let mut f = BufWriter::new(File::create(&path)?);
-                writeln!(f, "{{\n  global:")?;
-                for sym in self.info.exports[&crate_type].iter() {
-                    debug!("    {};", sym);
-                    writeln!(f, "    {};", sym)?;
-                }
-                writeln!(f, "\n  local:\n    *;\n}};")?;
-                Ok(())
-            })();
-            if let Err(e) = res {
-                self.sess.fatal(&format!("failed to write version script: {}", e));
-            }
-        }
-
-        if self.sess.target.target.options.is_like_osx {
-            if !self.is_ld {
-                arg.push("-Wl,")
-            }
-            arg.push("-exported_symbols_list,");
-        } else if self.sess.target.target.options.is_like_solaris {
-            if !self.is_ld {
-                arg.push("-Wl,")
-            }
-            arg.push("-M,");
-        } else {
-            if !self.is_ld {
-                arg.push("-Wl,")
-            }
-            arg.push("--version-script=");
-        }
-
-        arg.push(&path);
-        self.cmd.arg(arg);
-    }
-
-    fn subsystem(&mut self, subsystem: &str) {
-        self.linker_arg("--subsystem");
-        self.linker_arg(&subsystem);
-    }
-
-    fn finalize(&mut self) -> Command {
-        self.hint_dynamic(); // Reset to default before returning the composed command line.
-        let mut cmd = Command::new("");
-        ::std::mem::swap(&mut cmd, &mut self.cmd);
-        cmd
-    }
-
-    fn group_start(&mut self) {
-        if !self.sess.target.target.options.is_like_osx {
-            self.linker_arg("--start-group");
-        }
-    }
-
-    fn group_end(&mut self) {
-        if !self.sess.target.target.options.is_like_osx {
-            self.linker_arg("--end-group");
-        }
-    }
-
-    fn cross_lang_lto(&mut self) {
-        match self.sess.opts.debugging_opts.cross_lang_lto {
-            CrossLangLto::Disabled => {
-                // Nothing to do
-            }
-            CrossLangLto::LinkerPluginAuto => {
-                self.push_cross_lang_lto_args(None);
-            }
-            CrossLangLto::LinkerPlugin(ref path) => {
-                self.push_cross_lang_lto_args(Some(path.as_os_str()));
-            }
-        }
-    }
-}
-
-pub struct MsvcLinker<'a> {
-    cmd: Command,
-    sess: &'a Session,
-    info: &'a LinkerInfo
-}
-
-impl<'a> Linker for MsvcLinker<'a> {
-    fn link_rlib(&mut self, lib: &Path) { self.cmd.arg(lib); }
-    fn add_object(&mut self, path: &Path) { self.cmd.arg(path); }
-    fn args(&mut self, args: &[String]) { self.cmd.args(args); }
-
-    fn build_dylib(&mut self, out_filename: &Path) {
-        self.cmd.arg("/DLL");
-        let mut arg: OsString = "/IMPLIB:".into();
-        arg.push(out_filename.with_extension("dll.lib"));
-        self.cmd.arg(arg);
-    }
-
-    fn build_static_executable(&mut self) {
-        // noop
-    }
-
-    fn gc_sections(&mut self, _keep_metadata: bool) {
-        // MSVC's ICF (Identical COMDAT Folding) link optimization is
-        // slow for Rust and thus we disable it by default when not in
-        // optimization build.
-        if self.sess.opts.optimize != config::OptLevel::No {
-            self.cmd.arg("/OPT:REF,ICF");
-        } else {
-            // It is necessary to specify NOICF here, because /OPT:REF
-            // implies ICF by default.
-            self.cmd.arg("/OPT:REF,NOICF");
-        }
-    }
-
-    fn link_dylib(&mut self, lib: &str) {
-        self.cmd.arg(&format!("{}.lib", lib));
-    }
-
-    fn link_rust_dylib(&mut self, lib: &str, path: &Path) {
-        // When producing a dll, the MSVC linker may not actually emit a
-        // `foo.lib` file if the dll doesn't actually export any symbols, so we
-        // check to see if the file is there and just omit linking to it if it's
-        // not present.
-        let name = format!("{}.dll.lib", lib);
-        if fs::metadata(&path.join(&name)).is_ok() {
-            self.cmd.arg(name);
-        }
-    }
-
-    fn link_staticlib(&mut self, lib: &str) {
-        self.cmd.arg(&format!("{}.lib", lib));
-    }
-
-    fn position_independent_executable(&mut self) {
-        // noop
-    }
-
-    fn no_position_independent_executable(&mut self) {
-        // noop
-    }
-
-    fn full_relro(&mut self) {
-        // noop
-    }
-
-    fn partial_relro(&mut self) {
-        // noop
-    }
-
-    fn no_relro(&mut self) {
-        // noop
-    }
-
-    fn no_default_libraries(&mut self) {
-        // Currently we don't pass the /NODEFAULTLIB flag to the linker on MSVC
-        // as there's been trouble in the past of linking the C++ standard
-        // library required by LLVM. This likely needs to happen one day, but
-        // in general Windows is also a more controlled environment than
-        // Unix, so it's not necessarily as critical that this be implemented.
-        //
-        // Note that there are also some licensing worries about statically
-        // linking some libraries which require a specific agreement, so it may
-        // not ever be possible for us to pass this flag.
-    }
-
-    fn include_path(&mut self, path: &Path) {
-        let mut arg = OsString::from("/LIBPATH:");
-        arg.push(path);
-        self.cmd.arg(&arg);
-    }
-
-    fn output_filename(&mut self, path: &Path) {
-        let mut arg = OsString::from("/OUT:");
-        arg.push(path);
-        self.cmd.arg(&arg);
-    }
-
-    fn framework_path(&mut self, _path: &Path) {
-        bug!("frameworks are not supported on windows")
-    }
-    fn link_framework(&mut self, _framework: &str) {
-        bug!("frameworks are not supported on windows")
-    }
-
-    fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) {
-        // not supported?
-        self.link_staticlib(lib);
-    }
-    fn link_whole_rlib(&mut self, path: &Path) {
-        // not supported?
-        self.link_rlib(path);
-    }
-    fn optimize(&mut self) {
-        // Needs more investigation of `/OPT` arguments
-    }
-
-    fn pgo_gen(&mut self) {
-        // Nothing needed here.
-    }
-
-    fn debuginfo(&mut self) {
-        // This will cause the Microsoft linker to generate a PDB file
-        // from the CodeView line tables in the object files.
-        self.cmd.arg("/DEBUG");
-
-        // This will cause the Microsoft linker to embed .natvis info into the the PDB file
-        let sysroot = self.sess.sysroot();
-        let natvis_dir_path = sysroot.join("lib\\rustlib\\etc");
-        if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) {
-            // LLVM 5.0.0's lld-link frontend doesn't yet recognize, and chokes
-            // on, the /NATVIS:... flags.  LLVM 6 (or earlier) should at worst ignore
-            // them, eventually mooting this workaround, per this landed patch:
-            // https://github.com/llvm-mirror/lld/commit/27b9c4285364d8d76bb43839daa100
-            if let Some(ref linker_path) = self.sess.opts.cg.linker {
-                if let Some(linker_name) = Path::new(&linker_path).file_stem() {
-                    if linker_name.to_str().unwrap().to_lowercase() == "lld-link" {
-                        self.sess.warn("not embedding natvis: lld-link may not support the flag");
-                        return;
-                    }
-                }
-            }
-            for entry in natvis_dir {
-                match entry {
-                    Ok(entry) => {
-                        let path = entry.path();
-                        if path.extension() == Some("natvis".as_ref()) {
-                            let mut arg = OsString::from("/NATVIS:");
-                            arg.push(path);
-                            self.cmd.arg(arg);
-                        }
-                    },
-                    Err(err) => {
-                        self.sess.warn(&format!("error enumerating natvis directory: {}", err));
-                    },
-                }
-            }
-        }
-    }
-
-    // Currently the compiler doesn't use `dllexport` (an LLVM attribute) to
-    // export symbols from a dynamic library. When building a dynamic library,
-    // however, we're going to want some symbols exported, so this function
-    // generates a DEF file which lists all the symbols.
-    //
-    // The linker will read this `*.def` file and export all the symbols from
-    // the dynamic library. Note that this is not as simple as just exporting
-    // all the symbols in the current crate (as specified by `codegen.reachable`)
-    // but rather we also need to possibly export the symbols of upstream
-    // crates. Upstream rlibs may be linked statically to this dynamic library,
-    // in which case they may continue to transitively be used and hence need
-    // their symbols exported.
-    fn export_symbols(&mut self,
-                      tmpdir: &Path,
-                      crate_type: CrateType) {
-        let path = tmpdir.join("lib.def");
-        let res = (|| -> io::Result<()> {
-            let mut f = BufWriter::new(File::create(&path)?);
-
-            // Start off with the standard module name header and then go
-            // straight to exports.
-            writeln!(f, "LIBRARY")?;
-            writeln!(f, "EXPORTS")?;
-            for symbol in self.info.exports[&crate_type].iter() {
-                debug!("  _{}", symbol);
-                writeln!(f, "  {}", symbol)?;
-            }
-            Ok(())
-        })();
-        if let Err(e) = res {
-            self.sess.fatal(&format!("failed to write lib.def file: {}", e));
-        }
-        let mut arg = OsString::from("/DEF:");
-        arg.push(path);
-        self.cmd.arg(&arg);
-    }
-
-    fn subsystem(&mut self, subsystem: &str) {
-        // Note that previous passes of the compiler validated this subsystem,
-        // so we just blindly pass it to the linker.
-        self.cmd.arg(&format!("/SUBSYSTEM:{}", subsystem));
-
-        // Windows has two subsystems we're interested in right now, the console
-        // and windows subsystems. These both implicitly have different entry
-        // points (starting symbols). The console entry point starts with
-        // `mainCRTStartup` and the windows entry point starts with
-        // `WinMainCRTStartup`. These entry points, defined in system libraries,
-        // will then later probe for either `main` or `WinMain`, respectively to
-        // start the application.
-        //
-        // In Rust we just always generate a `main` function so we want control
-        // to always start there, so we force the entry point on the windows
-        // subsystem to be `mainCRTStartup` to get everything booted up
-        // correctly.
-        //
-        // For more information see RFC #1665
-        if subsystem == "windows" {
-            self.cmd.arg("/ENTRY:mainCRTStartup");
-        }
-    }
-
-    fn finalize(&mut self) -> Command {
-        let mut cmd = Command::new("");
-        ::std::mem::swap(&mut cmd, &mut self.cmd);
-        cmd
-    }
-
-    // MSVC doesn't need group indicators
-    fn group_start(&mut self) {}
-    fn group_end(&mut self) {}
-
-    fn cross_lang_lto(&mut self) {
-        // Do nothing
-    }
-}
-
-pub struct EmLinker<'a> {
-    cmd: Command,
-    sess: &'a Session,
-    info: &'a LinkerInfo
-}
-
-impl<'a> Linker for EmLinker<'a> {
-    fn include_path(&mut self, path: &Path) {
-        self.cmd.arg("-L").arg(path);
-    }
-
-    fn link_staticlib(&mut self, lib: &str) {
-        self.cmd.arg("-l").arg(lib);
-    }
-
-    fn output_filename(&mut self, path: &Path) {
-        self.cmd.arg("-o").arg(path);
-    }
-
-    fn add_object(&mut self, path: &Path) {
-        self.cmd.arg(path);
-    }
-
-    fn link_dylib(&mut self, lib: &str) {
-        // Emscripten always links statically
-        self.link_staticlib(lib);
-    }
-
-    fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) {
-        // not supported?
-        self.link_staticlib(lib);
-    }
-
-    fn link_whole_rlib(&mut self, lib: &Path) {
-        // not supported?
-        self.link_rlib(lib);
-    }
-
-    fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
-        self.link_dylib(lib);
-    }
-
-    fn link_rlib(&mut self, lib: &Path) {
-        self.add_object(lib);
-    }
-
-    fn position_independent_executable(&mut self) {
-        // noop
-    }
-
-    fn no_position_independent_executable(&mut self) {
-        // noop
-    }
-
-    fn full_relro(&mut self) {
-        // noop
-    }
-
-    fn partial_relro(&mut self) {
-        // noop
-    }
-
-    fn no_relro(&mut self) {
-        // noop
-    }
-
-    fn args(&mut self, args: &[String]) {
-        self.cmd.args(args);
-    }
-
-    fn framework_path(&mut self, _path: &Path) {
-        bug!("frameworks are not supported on Emscripten")
-    }
-
-    fn link_framework(&mut self, _framework: &str) {
-        bug!("frameworks are not supported on Emscripten")
-    }
-
-    fn gc_sections(&mut self, _keep_metadata: bool) {
-        // noop
-    }
-
-    fn optimize(&mut self) {
-        // Emscripten performs own optimizations
-        self.cmd.arg(match self.sess.opts.optimize {
-            OptLevel::No => "-O0",
-            OptLevel::Less => "-O1",
-            OptLevel::Default => "-O2",
-            OptLevel::Aggressive => "-O3",
-            OptLevel::Size => "-Os",
-            OptLevel::SizeMin => "-Oz"
-        });
-        // Unusable until https://github.com/rust-lang/rust/issues/38454 is resolved
-        self.cmd.args(&["--memory-init-file", "0"]);
-    }
-
-    fn pgo_gen(&mut self) {
-        // noop, but maybe we need something like the gnu linker?
-    }
-
-    fn debuginfo(&mut self) {
-        // Preserve names or generate source maps depending on debug info
-        self.cmd.arg(match self.sess.opts.debuginfo {
-            DebugInfo::None => "-g0",
-            DebugInfo::Limited => "-g3",
-            DebugInfo::Full => "-g4"
-        });
-    }
-
-    fn no_default_libraries(&mut self) {
-        self.cmd.args(&["-s", "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]"]);
-    }
-
-    fn build_dylib(&mut self, _out_filename: &Path) {
-        bug!("building dynamic library is unsupported on Emscripten")
-    }
-
-    fn build_static_executable(&mut self) {
-        // noop
-    }
-
-    fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) {
-        let symbols = &self.info.exports[&crate_type];
-
-        debug!("EXPORTED SYMBOLS:");
-
-        self.cmd.arg("-s");
-
-        let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
-        let mut encoded = String::new();
-
-        {
-            let mut encoder = json::Encoder::new(&mut encoded);
-            let res = encoder.emit_seq(symbols.len(), |encoder| {
-                for (i, sym) in symbols.iter().enumerate() {
-                    encoder.emit_seq_elt(i, |encoder| {
-                        encoder.emit_str(&("_".to_string() + sym))
-                    })?;
-                }
-                Ok(())
-            });
-            if let Err(e) = res {
-                self.sess.fatal(&format!("failed to encode exported symbols: {}", e));
-            }
-        }
-        debug!("{}", encoded);
-        arg.push(encoded);
-
-        self.cmd.arg(arg);
-    }
-
-    fn subsystem(&mut self, _subsystem: &str) {
-        // noop
-    }
-
-    fn finalize(&mut self) -> Command {
-        let mut cmd = Command::new("");
-        ::std::mem::swap(&mut cmd, &mut self.cmd);
-        cmd
-    }
-
-    // Appears not necessary on Emscripten
-    fn group_start(&mut self) {}
-    fn group_end(&mut self) {}
-
-    fn cross_lang_lto(&mut self) {
-        // Do nothing
-    }
-}
-
-fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec<String> {
-    let mut symbols = Vec::new();
-
-    let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
-    for &(symbol, level) in tcx.exported_symbols(LOCAL_CRATE).iter() {
-        if level.is_below_threshold(export_threshold) {
-            symbols.push(symbol.symbol_name(tcx).to_string());
-        }
-    }
-
-    let formats = tcx.sess.dependency_formats.borrow();
-    let deps = formats[&crate_type].iter();
-
-    for (index, dep_format) in deps.enumerate() {
-        let cnum = CrateNum::new(index + 1);
-        // For each dependency that we are linking to statically ...
-        if *dep_format == Linkage::Static {
-            // ... we add its symbol list to our export list.
-            for &(symbol, level) in tcx.exported_symbols(cnum).iter() {
-                if level.is_below_threshold(export_threshold) {
-                    symbols.push(symbol.symbol_name(tcx).to_string());
-                }
-            }
-        }
-    }
-
-    symbols
-}
-
-pub struct WasmLd<'a> {
-    cmd: Command,
-    sess: &'a Session,
-    info: &'a LinkerInfo,
-}
-
-impl<'a> Linker for WasmLd<'a> {
-    fn link_dylib(&mut self, lib: &str) {
-        self.cmd.arg("-l").arg(lib);
-    }
-
-    fn link_staticlib(&mut self, lib: &str) {
-        self.cmd.arg("-l").arg(lib);
-    }
-
-    fn link_rlib(&mut self, lib: &Path) {
-        self.cmd.arg(lib);
-    }
-
-    fn include_path(&mut self, path: &Path) {
-        self.cmd.arg("-L").arg(path);
-    }
-
-    fn framework_path(&mut self, _path: &Path) {
-        panic!("frameworks not supported")
-    }
-
-    fn output_filename(&mut self, path: &Path) {
-        self.cmd.arg("-o").arg(path);
-    }
-
-    fn add_object(&mut self, path: &Path) {
-        self.cmd.arg(path);
-    }
-
-    fn position_independent_executable(&mut self) {
-    }
-
-    fn full_relro(&mut self) {
-    }
-
-    fn partial_relro(&mut self) {
-    }
-
-    fn no_relro(&mut self) {
-    }
-
-    fn build_static_executable(&mut self) {
-    }
-
-    fn args(&mut self, args: &[String]) {
-        self.cmd.args(args);
-    }
-
-    fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
-        self.cmd.arg("-l").arg(lib);
-    }
-
-    fn link_framework(&mut self, _framework: &str) {
-        panic!("frameworks not supported")
-    }
-
-    fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) {
-        self.cmd.arg("-l").arg(lib);
-    }
-
-    fn link_whole_rlib(&mut self, lib: &Path) {
-        self.cmd.arg(lib);
-    }
-
-    fn gc_sections(&mut self, _keep_metadata: bool) {
-        self.cmd.arg("--gc-sections");
-    }
-
-    fn optimize(&mut self) {
-        self.cmd.arg(match self.sess.opts.optimize {
-            OptLevel::No => "-O0",
-            OptLevel::Less => "-O1",
-            OptLevel::Default => "-O2",
-            OptLevel::Aggressive => "-O3",
-            // Currently LLD doesn't support `Os` and `Oz`, so pass through `O2`
-            // instead.
-            OptLevel::Size => "-O2",
-            OptLevel::SizeMin => "-O2"
-        });
-    }
-
-    fn pgo_gen(&mut self) {
-    }
-
-    fn debuginfo(&mut self) {
-    }
-
-    fn no_default_libraries(&mut self) {
-    }
-
-    fn build_dylib(&mut self, _out_filename: &Path) {
-    }
-
-    fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) {
-        for sym in self.info.exports[&crate_type].iter() {
-            self.cmd.arg("--export").arg(&sym);
-        }
-    }
-
-    fn subsystem(&mut self, _subsystem: &str) {
-    }
-
-    fn no_position_independent_executable(&mut self) {
-    }
-
-    fn finalize(&mut self) -> Command {
-        // There have been reports in the wild (rustwasm/wasm-bindgen#119) of
-        // using threads causing weird hangs and bugs. Disable it entirely as
-        // this isn't yet the bottleneck of compilation at all anyway.
-        self.cmd.arg("--no-threads");
-
-        // By default LLD only gives us one page of stack (64k) which is a
-        // little small. Default to a larger stack closer to other PC platforms
-        // (1MB) and users can always inject their own link-args to override this.
-        self.cmd.arg("-z").arg("stack-size=1048576");
-
-        // By default LLD's memory layout is:
-        //
-        // 1. First, a blank page
-        // 2. Next, all static data
-        // 3. Finally, the main stack (which grows down)
-        //
-        // This has the unfortunate consequence that on stack overflows you
-        // corrupt static data and can cause some exceedingly weird bugs. To
-        // help detect this a little sooner we instead request that the stack is
-        // placed before static data.
-        //
-        // This means that we'll generate slightly larger binaries as references
-        // to static data will take more bytes in the ULEB128 encoding, but
-        // stack overflow will be guaranteed to trap as it underflows instead of
-        // corrupting static data.
-        self.cmd.arg("--stack-first");
-
-        // FIXME we probably shouldn't pass this but instead pass an explicit
-        // whitelist of symbols we'll allow to be undefined. Unfortunately
-        // though we can't handle symbols like `log10` that LLVM injects at a
-        // super late date without actually parsing object files. For now let's
-        // stick to this and hopefully fix it before stabilization happens.
-        self.cmd.arg("--allow-undefined");
-
-        // For now we just never have an entry symbol
-        self.cmd.arg("--no-entry");
-
-        // Make the default table accessible
-        self.cmd.arg("--export-table");
-
-        // Rust code should never have warnings, and warnings are often
-        // indicative of bugs, let's prevent them.
-        self.cmd.arg("--fatal-warnings");
-
-        let mut cmd = Command::new("");
-        ::std::mem::swap(&mut cmd, &mut self.cmd);
-        cmd
-    }
-
-    // Not needed for now with LLD
-    fn group_start(&mut self) {}
-    fn group_end(&mut self) {}
-
-    fn cross_lang_lto(&mut self) {
-        // Do nothing for now
-    }
-}
diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs
index 3ac22f4eaef..60b06c579cb 100644
--- a/src/librustc_codegen_llvm/back/lto.rs
+++ b/src/librustc_codegen_llvm/back/lto.rs
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 use back::bytecode::{DecodedBytecode, RLIB_BYTECODE_EXTENSION};
-use back::symbol_export;
 use back::write::{ModuleConfig, with_llvm_pmb, CodegenContext};
 use back::write::{self, DiagnosticHandlers, pre_lto_bitcode_filename};
 use errors::{FatalError, Handler};
@@ -24,6 +23,7 @@ use rustc::middle::exported_symbols::SymbolExportLevel;
 use rustc::session::config::{self, Lto};
 use rustc::util::common::time_ext;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_codegen_utils::symbol_export;
 use time_graph::Timeline;
 use {ModuleCodegen, ModuleLlvm, ModuleKind};
 
@@ -205,11 +205,11 @@ pub(crate) fn run(cgcx: &CodegenContext,
         Lto::Fat => {
             assert!(cached_modules.is_empty());
             let opt_jobs = fat_lto(cgcx,
-                                  &diag_handler,
-                                  modules,
-                                  upstream_modules,
-                                  &symbol_white_list,
-                                  timeline);
+                                   &diag_handler,
+                                   modules,
+                                   upstream_modules,
+                                   &symbol_white_list,
+                                   timeline);
             opt_jobs.map(|opt_jobs| (opt_jobs, vec![]))
         }
         Lto::Thin |
@@ -296,7 +296,7 @@ fn fat_lto(cgcx: &CodegenContext,
                 let data = bc_decoded.data();
                 linker.add(&data).map_err(|()| {
                     let msg = format!("failed to load bc of {:?}", name);
-                    write::llvm_err(&diag_handler, msg)
+                    write::llvm_err(&diag_handler, &msg)
                 })
             })?;
             timeline.record(&format!("link {:?}", name));
@@ -310,8 +310,8 @@ fn fat_lto(cgcx: &CodegenContext,
         unsafe {
             let ptr = symbol_white_list.as_ptr();
             llvm::LLVMRustRunRestrictionPass(llmod,
-                                            ptr as *const *const libc::c_char,
-                                            symbol_white_list.len() as libc::size_t);
+                                             ptr as *const *const libc::c_char,
+                                             symbol_white_list.len() as libc::size_t);
             cgcx.save_temp_bitcode(&module, "lto.after-restriction");
         }
 
@@ -490,7 +490,7 @@ fn thin_lto(cgcx: &CodegenContext,
             symbol_white_list.as_ptr(),
             symbol_white_list.len() as u32,
         ).ok_or_else(|| {
-            write::llvm_err(&diag_handler, "failed to prepare thin LTO context".to_string())
+            write::llvm_err(&diag_handler, "failed to prepare thin LTO context")
         })?;
 
         info!("thin LTO data created");
@@ -502,7 +502,7 @@ fn thin_lto(cgcx: &CodegenContext,
             // If we don't compile incrementally, we don't need to load the
             // import data from LLVM.
             assert!(green_modules.is_empty());
-            ThinLTOImports::new()
+            ThinLTOImports::default()
         };
         info!("thin LTO import map loaded");
         timeline.record("import-map-loaded");
@@ -595,9 +595,7 @@ fn run_pass_manager(cgcx: &CodegenContext,
         };
         with_llvm_pmb(llmod, config, opt_level, false, &mut |b| {
             if thin {
-                if !llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm) {
-                    panic!("this version of LLVM does not support ThinLTO");
-                }
+                llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm);
             } else {
                 llvm::LLVMPassManagerBuilderPopulateLTOPassManager(b, pm,
                     /* Internalize = */ False,
@@ -605,13 +603,19 @@ fn run_pass_manager(cgcx: &CodegenContext,
             }
         });
 
+        // We always generate bitcode through ThinLTOBuffers,
+        // which do not support anonymous globals
+        if config.bitcode_needed() {
+            let pass = llvm::LLVMRustFindAndCreatePass("name-anon-globals\0".as_ptr() as *const _);
+            llvm::LLVMRustAddPass(pm, pass.unwrap());
+        }
+
         if config.verify_llvm_ir {
             let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _);
             llvm::LLVMRustAddPass(pm, pass.unwrap());
         }
 
-        time_ext(cgcx.time_passes, None, "LTO passes", ||
-             llvm::LLVMRunPassManager(pm, llmod));
+        time_ext(cgcx.time_passes, None, "LTO passes", || llvm::LLVMRunPassManager(pm, llmod));
 
         llvm::LLVMDisposePassManager(pm);
     }
@@ -740,7 +744,7 @@ impl ThinModule {
     {
         let diag_handler = cgcx.create_diag_handler();
         let tm = (cgcx.tm_factory)().map_err(|e| {
-            write::llvm_err(&diag_handler, e)
+            write::llvm_err(&diag_handler, &e)
         })?;
 
         // Right now the implementation we've got only works over serialized
@@ -755,7 +759,7 @@ impl ThinModule {
             self.data().len(),
             self.shared.module_names[self.idx].as_ptr(),
         ).ok_or_else(|| {
-            let msg = "failed to parse bitcode for thin LTO module".to_string();
+            let msg = "failed to parse bitcode for thin LTO module";
             write::llvm_err(&diag_handler, msg)
         })? as *const _;
         let module = ModuleCodegen {
@@ -779,7 +783,7 @@ impl ThinModule {
             let mut cu2 = ptr::null_mut();
             llvm::LLVMRustThinLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2);
             if !cu2.is_null() {
-                let msg = "multiple source DICompileUnits found".to_string();
+                let msg = "multiple source DICompileUnits found";
                 return Err(write::llvm_err(&diag_handler, msg))
             }
 
@@ -800,25 +804,25 @@ impl ThinModule {
             // You can find some more comments about these functions in the LLVM
             // bindings we've got (currently `PassWrapper.cpp`)
             if !llvm::LLVMRustPrepareThinLTORename(self.shared.data.0, llmod) {
-                let msg = "failed to prepare thin LTO module".to_string();
+                let msg = "failed to prepare thin LTO module";
                 return Err(write::llvm_err(&diag_handler, msg))
             }
             cgcx.save_temp_bitcode(&module, "thin-lto-after-rename");
             timeline.record("rename");
             if !llvm::LLVMRustPrepareThinLTOResolveWeak(self.shared.data.0, llmod) {
-                let msg = "failed to prepare thin LTO module".to_string();
+                let msg = "failed to prepare thin LTO module";
                 return Err(write::llvm_err(&diag_handler, msg))
             }
             cgcx.save_temp_bitcode(&module, "thin-lto-after-resolve");
             timeline.record("resolve");
             if !llvm::LLVMRustPrepareThinLTOInternalize(self.shared.data.0, llmod) {
-                let msg = "failed to prepare thin LTO module".to_string();
+                let msg = "failed to prepare thin LTO module";
                 return Err(write::llvm_err(&diag_handler, msg))
             }
             cgcx.save_temp_bitcode(&module, "thin-lto-after-internalize");
             timeline.record("internalize");
             if !llvm::LLVMRustPrepareThinLTOImport(self.shared.data.0, llmod) {
-                let msg = "failed to prepare thin LTO module".to_string();
+                let msg = "failed to prepare thin LTO module";
                 return Err(write::llvm_err(&diag_handler, msg))
             }
             cgcx.save_temp_bitcode(&module, "thin-lto-after-import");
@@ -873,19 +877,13 @@ impl ThinModule {
     }
 }
 
-#[derive(Debug)]
+#[derive(Debug, Default)]
 pub struct ThinLTOImports {
     // key = llvm name of importing module, value = list of modules it imports from
     imports: FxHashMap<String, Vec<String>>,
 }
 
 impl ThinLTOImports {
-    fn new() -> ThinLTOImports {
-        ThinLTOImports {
-            imports: FxHashMap(),
-        }
-    }
-
     fn modules_imported_by(&self, llvm_module_name: &str) -> &[String] {
         self.imports.get(llvm_module_name).map(|v| &v[..]).unwrap_or(&[])
     }
@@ -910,9 +908,7 @@ impl ThinLTOImports {
                .unwrap()
                .push(imported_module_name.to_owned());
         }
-        let mut map = ThinLTOImports {
-            imports: FxHashMap(),
-        };
+        let mut map = ThinLTOImports::default();
         llvm::LLVMRustGetThinLTOModuleImports(data,
                                               imported_module_callback,
                                               &mut map as *mut _ as *mut libc::c_void);
@@ -921,12 +917,6 @@ impl ThinLTOImports {
 }
 
 fn module_name_to_str(c_str: &CStr) -> &str {
-    match c_str.to_str() {
-        Ok(s) => s,
-        Err(e) => {
-            bug!("Encountered non-utf8 LLVM module name `{}`: {}",
-                c_str.to_string_lossy(),
-                e)
-        }
-    }
+    c_str.to_str().unwrap_or_else(|e|
+        bug!("Encountered non-utf8 LLVM module name `{}`: {}", c_str.to_string_lossy(), e))
 }
diff --git a/src/librustc_codegen_llvm/back/rpath.rs b/src/librustc_codegen_llvm/back/rpath.rs
index aa4f7688b0f..ee4a9b30a1a 100644
--- a/src/librustc_codegen_llvm/back/rpath.rs
+++ b/src/librustc_codegen_llvm/back/rpath.rs
@@ -42,7 +42,7 @@ pub fn get_rpath_flags(config: &mut RPathConfig) -> Vec<String> {
 
     // Use DT_RUNPATH instead of DT_RPATH if available
     if config.linker_is_gnu {
-        flags.push("-Wl,--enable-new-dtags".to_string());
+        flags.push("-Wl,--enable-new-dtags".to_owned());
     }
 
     flags
@@ -59,7 +59,8 @@ fn rpaths_to_flags(rpaths: &[String]) -> Vec<String> {
             ret.push(format!("-Wl,-rpath,{}", &(*rpath)));
         }
     }
-    return ret;
+
+    ret
 }
 
 fn get_rpaths(config: &mut RPathConfig, libs: &[PathBuf]) -> Vec<String> {
@@ -92,7 +93,8 @@ fn get_rpaths(config: &mut RPathConfig, libs: &[PathBuf]) -> Vec<String> {
 
     // Remove duplicates
     let rpaths = minimize_rpaths(&rpaths);
-    return rpaths;
+
+    rpaths
 }
 
 fn get_rpaths_relative_to_output(config: &mut RPathConfig,
@@ -109,7 +111,7 @@ fn get_rpath_relative_to_output(config: &mut RPathConfig, lib: &Path) -> String
     };
 
     let cwd = env::current_dir().unwrap();
-    let mut lib = fs::canonicalize(&cwd.join(lib)).unwrap_or(cwd.join(lib));
+    let mut lib = fs::canonicalize(&cwd.join(lib)).unwrap_or_else(|_| cwd.join(lib));
     lib.pop();
     let mut output = cwd.join(&config.out_filename);
     output.pop();
@@ -117,8 +119,7 @@ fn get_rpath_relative_to_output(config: &mut RPathConfig, lib: &Path) -> String
     let relative = path_relative_from(&lib, &output).unwrap_or_else(||
         panic!("couldn't create relative path from {:?} to {:?}", output, lib));
     // FIXME (#9639): This needs to handle non-utf8 paths
-    format!("{}/{}", prefix,
-            relative.to_str().expect("non-utf8 component in path"))
+    format!("{}/{}", prefix, relative.to_str().expect("non-utf8 component in path"))
 }
 
 // This routine is adapted from the *old* Path's `path_relative_from`
@@ -168,7 +169,7 @@ fn get_install_prefix_rpath(config: &mut RPathConfig) -> String {
     let path = (config.get_install_prefix_lib_path)();
     let path = env::current_dir().unwrap().join(&path);
     // FIXME (#9639): This needs to handle non-utf8 paths
-    path.to_str().expect("non-utf8 component in rpath").to_string()
+    path.to_str().expect("non-utf8 component in rpath").to_owned()
 }
 
 fn minimize_rpaths(rpaths: &[String]) -> Vec<String> {
diff --git a/src/librustc_codegen_llvm/back/symbol_export.rs b/src/librustc_codegen_llvm/back/symbol_export.rs
deleted file mode 100644
index 6b1b0b94fd9..00000000000
--- a/src/librustc_codegen_llvm/back/symbol_export.rs
+++ /dev/null
@@ -1,395 +0,0 @@
-// Copyright 2016 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use rustc_data_structures::sync::Lrc;
-use std::sync::Arc;
-
-use monomorphize::Instance;
-use rustc::hir;
-use rustc::hir::Node;
-use rustc::hir::CodegenFnAttrFlags;
-use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX};
-use rustc_data_structures::fingerprint::Fingerprint;
-use rustc::middle::exported_symbols::{SymbolExportLevel, ExportedSymbol, metadata_symbol_name};
-use rustc::session::config;
-use rustc::ty::{TyCtxt, SymbolName};
-use rustc::ty::query::Providers;
-use rustc::ty::subst::Substs;
-use rustc::util::nodemap::{FxHashMap, DefIdMap};
-use rustc_allocator::ALLOCATOR_METHODS;
-use rustc_data_structures::indexed_vec::IndexVec;
-use std::collections::hash_map::Entry::*;
-
-pub type ExportedSymbols = FxHashMap<
-    CrateNum,
-    Arc<Vec<(String, SymbolExportLevel)>>,
->;
-
-pub fn threshold(tcx: TyCtxt) -> SymbolExportLevel {
-    crates_export_threshold(&tcx.sess.crate_types.borrow())
-}
-
-fn crate_export_threshold(crate_type: config::CrateType) -> SymbolExportLevel {
-    match crate_type {
-        config::CrateType::Executable |
-        config::CrateType::Staticlib  |
-        config::CrateType::ProcMacro  |
-        config::CrateType::Cdylib     => SymbolExportLevel::C,
-        config::CrateType::Rlib       |
-        config::CrateType::Dylib      => SymbolExportLevel::Rust,
-    }
-}
-
-pub fn crates_export_threshold(crate_types: &[config::CrateType])
-                                      -> SymbolExportLevel {
-    if crate_types.iter().any(|&crate_type| {
-        crate_export_threshold(crate_type) == SymbolExportLevel::Rust
-    }) {
-        SymbolExportLevel::Rust
-    } else {
-        SymbolExportLevel::C
-    }
-}
-
-fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                             cnum: CrateNum)
-                                             -> Lrc<DefIdMap<SymbolExportLevel>>
-{
-    assert_eq!(cnum, LOCAL_CRATE);
-
-    if !tcx.sess.opts.output_types.should_codegen() {
-        return Lrc::new(DefIdMap())
-    }
-
-    // Check to see if this crate is a "special runtime crate". These
-    // crates, implementation details of the standard library, typically
-    // have a bunch of `pub extern` and `#[no_mangle]` functions as the
-    // ABI between them. We don't want their symbols to have a `C`
-    // export level, however, as they're just implementation details.
-    // Down below we'll hardwire all of the symbols to the `Rust` export
-    // level instead.
-    let special_runtime_crate = tcx.is_panic_runtime(LOCAL_CRATE) ||
-        tcx.is_compiler_builtins(LOCAL_CRATE);
-
-    let mut reachable_non_generics: DefIdMap<_> = tcx.reachable_set(LOCAL_CRATE).0
-        .iter()
-        .filter_map(|&node_id| {
-            // We want to ignore some FFI functions that are not exposed from
-            // this crate. Reachable FFI functions can be lumped into two
-            // categories:
-            //
-            // 1. Those that are included statically via a static library
-            // 2. Those included otherwise (e.g. dynamically or via a framework)
-            //
-            // Although our LLVM module is not literally emitting code for the
-            // statically included symbols, it's an export of our library which
-            // needs to be passed on to the linker and encoded in the metadata.
-            //
-            // As a result, if this id is an FFI item (foreign item) then we only
-            // let it through if it's included statically.
-            match tcx.hir.get(node_id) {
-                Node::ForeignItem(..) => {
-                    let def_id = tcx.hir.local_def_id(node_id);
-                    if tcx.is_statically_included_foreign_item(def_id) {
-                        Some(def_id)
-                    } else {
-                        None
-                    }
-                }
-
-                // Only consider nodes that actually have exported symbols.
-                Node::Item(&hir::Item {
-                    node: hir::ItemKind::Static(..),
-                    ..
-                }) |
-                Node::Item(&hir::Item {
-                    node: hir::ItemKind::Fn(..), ..
-                }) |
-                Node::ImplItem(&hir::ImplItem {
-                    node: hir::ImplItemKind::Method(..),
-                    ..
-                }) => {
-                    let def_id = tcx.hir.local_def_id(node_id);
-                    let generics = tcx.generics_of(def_id);
-                    if !generics.requires_monomorphization(tcx) &&
-                        // Functions marked with #[inline] are only ever codegened
-                        // with "internal" linkage and are never exported.
-                        !Instance::mono(tcx, def_id).def.requires_local(tcx) {
-                        Some(def_id)
-                    } else {
-                        None
-                    }
-                }
-
-                _ => None
-            }
-        })
-        .map(|def_id| {
-            let export_level = if special_runtime_crate {
-                let name = tcx.symbol_name(Instance::mono(tcx, def_id)).as_str();
-                // We can probably do better here by just ensuring that
-                // it has hidden visibility rather than public
-                // visibility, as this is primarily here to ensure it's
-                // not stripped during LTO.
-                //
-                // In general though we won't link right if these
-                // symbols are stripped, and LTO currently strips them.
-                if &*name == "rust_eh_personality" ||
-                   &*name == "rust_eh_register_frames" ||
-                   &*name == "rust_eh_unregister_frames" {
-                    SymbolExportLevel::C
-                } else {
-                    SymbolExportLevel::Rust
-                }
-            } else {
-                symbol_export_level(tcx, def_id)
-            };
-            debug!("EXPORTED SYMBOL (local): {} ({:?})",
-                   tcx.symbol_name(Instance::mono(tcx, def_id)),
-                   export_level);
-            (def_id, export_level)
-        })
-        .collect();
-
-    if let Some(id) = *tcx.sess.derive_registrar_fn.get() {
-        let def_id = tcx.hir.local_def_id(id);
-        reachable_non_generics.insert(def_id, SymbolExportLevel::C);
-    }
-
-    if let Some(id) = *tcx.sess.plugin_registrar_fn.get() {
-        let def_id = tcx.hir.local_def_id(id);
-        reachable_non_generics.insert(def_id, SymbolExportLevel::C);
-    }
-
-    Lrc::new(reachable_non_generics)
-}
-
-fn is_reachable_non_generic_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                                     def_id: DefId)
-                                                     -> bool {
-    let export_threshold = threshold(tcx);
-
-    if let Some(&level) = tcx.reachable_non_generics(def_id.krate).get(&def_id) {
-        level.is_below_threshold(export_threshold)
-    } else {
-        false
-    }
-}
-
-fn is_reachable_non_generic_provider_extern<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                                      def_id: DefId)
-                                                      -> bool {
-    tcx.reachable_non_generics(def_id.krate).contains_key(&def_id)
-}
-
-fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                             cnum: CrateNum)
-                                             -> Arc<Vec<(ExportedSymbol<'tcx>,
-                                                         SymbolExportLevel)>>
-{
-    assert_eq!(cnum, LOCAL_CRATE);
-
-    if !tcx.sess.opts.output_types.should_codegen() {
-        return Arc::new(vec![])
-    }
-
-    let mut symbols: Vec<_> = tcx.reachable_non_generics(LOCAL_CRATE)
-                                 .iter()
-                                 .map(|(&def_id, &level)| {
-                                    (ExportedSymbol::NonGeneric(def_id), level)
-                                 })
-                                 .collect();
-
-    if tcx.sess.entry_fn.borrow().is_some() {
-        let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new("main"));
-
-        symbols.push((exported_symbol, SymbolExportLevel::C));
-    }
-
-    if tcx.sess.allocator_kind.get().is_some() {
-        for method in ALLOCATOR_METHODS {
-            let symbol_name = format!("__rust_{}", method.name);
-            let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name));
-
-            symbols.push((exported_symbol, SymbolExportLevel::Rust));
-        }
-    }
-
-    if tcx.sess.opts.debugging_opts.pgo_gen.is_some() {
-        // These are weak symbols that point to the profile version and the
-        // profile name, which need to be treated as exported so LTO doesn't nix
-        // them.
-        const PROFILER_WEAK_SYMBOLS: [&'static str; 2] = [
-            "__llvm_profile_raw_version",
-            "__llvm_profile_filename",
-        ];
-        for sym in &PROFILER_WEAK_SYMBOLS {
-            let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(sym));
-            symbols.push((exported_symbol, SymbolExportLevel::C));
-        }
-    }
-
-    if tcx.sess.crate_types.borrow().contains(&config::CrateType::Dylib) {
-        let symbol_name = metadata_symbol_name(tcx);
-        let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name));
-
-        symbols.push((exported_symbol, SymbolExportLevel::Rust));
-    }
-
-    if tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics() {
-        use rustc::mir::mono::{Linkage, Visibility, MonoItem};
-        use rustc::ty::InstanceDef;
-
-        // Normally, we require that shared monomorphizations are not hidden,
-        // because if we want to re-use a monomorphization from a Rust dylib, it
-        // needs to be exported.
-        // However, on platforms that don't allow for Rust dylibs, having
-        // external linkage is enough for monomorphization to be linked to.
-        let need_visibility = tcx.sess.target.target.options.dynamic_linking &&
-                              !tcx.sess.target.target.options.only_cdylib;
-
-        let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
-
-        for (mono_item, &(linkage, visibility)) in cgus.iter()
-                                                       .flat_map(|cgu| cgu.items().iter()) {
-            if linkage != Linkage::External {
-                // We can only re-use things with external linkage, otherwise
-                // we'll get a linker error
-                continue
-            }
-
-            if need_visibility && visibility == Visibility::Hidden {
-                // If we potentially share things from Rust dylibs, they must
-                // not be hidden
-                continue
-            }
-
-            if let &MonoItem::Fn(Instance {
-                def: InstanceDef::Item(def_id),
-                substs,
-            }) = mono_item {
-                if substs.types().next().is_some() {
-                    symbols.push((ExportedSymbol::Generic(def_id, substs),
-                                  SymbolExportLevel::Rust));
-                }
-            }
-        }
-    }
-
-    // Sort so we get a stable incr. comp. hash.
-    symbols.sort_unstable_by(|&(ref symbol1, ..), &(ref symbol2, ..)| {
-        symbol1.compare_stable(tcx, symbol2)
-    });
-
-    Arc::new(symbols)
-}
-
-fn upstream_monomorphizations_provider<'a, 'tcx>(
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    cnum: CrateNum)
-    -> Lrc<DefIdMap<Lrc<FxHashMap<&'tcx Substs<'tcx>, CrateNum>>>>
-{
-    debug_assert!(cnum == LOCAL_CRATE);
-
-    let cnums = tcx.all_crate_nums(LOCAL_CRATE);
-
-    let mut instances: DefIdMap<FxHashMap<_, _>> = DefIdMap();
-
-    let cnum_stable_ids: IndexVec<CrateNum, Fingerprint> = {
-        let mut cnum_stable_ids = IndexVec::from_elem_n(Fingerprint::ZERO,
-                                                        cnums.len() + 1);
-
-        for &cnum in cnums.iter() {
-            cnum_stable_ids[cnum] = tcx.def_path_hash(DefId {
-                krate: cnum,
-                index: CRATE_DEF_INDEX,
-            }).0;
-        }
-
-        cnum_stable_ids
-    };
-
-    for &cnum in cnums.iter() {
-        for &(ref exported_symbol, _) in tcx.exported_symbols(cnum).iter() {
-            if let &ExportedSymbol::Generic(def_id, substs) = exported_symbol {
-                let substs_map = instances.entry(def_id).or_default();
-
-                match substs_map.entry(substs) {
-                    Occupied(mut e) => {
-                        // If there are multiple monomorphizations available,
-                        // we select one deterministically.
-                        let other_cnum = *e.get();
-                        if cnum_stable_ids[other_cnum] > cnum_stable_ids[cnum] {
-                            e.insert(cnum);
-                        }
-                    }
-                    Vacant(e) => {
-                        e.insert(cnum);
-                    }
-                }
-            }
-        }
-    }
-
-    Lrc::new(instances.into_iter()
-                      .map(|(key, value)| (key, Lrc::new(value)))
-                      .collect())
-}
-
-fn upstream_monomorphizations_for_provider<'a, 'tcx>(
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    def_id: DefId)
-    -> Option<Lrc<FxHashMap<&'tcx Substs<'tcx>, CrateNum>>>
-{
-    debug_assert!(!def_id.is_local());
-    tcx.upstream_monomorphizations(LOCAL_CRATE)
-       .get(&def_id)
-       .cloned()
-}
-
-fn is_unreachable_local_definition_provider(tcx: TyCtxt, def_id: DefId) -> bool {
-    if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
-        !tcx.reachable_set(LOCAL_CRATE).0.contains(&node_id)
-    } else {
-        bug!("is_unreachable_local_definition called with non-local DefId: {:?}",
-              def_id)
-    }
-}
-
-pub fn provide(providers: &mut Providers) {
-    providers.reachable_non_generics = reachable_non_generics_provider;
-    providers.is_reachable_non_generic = is_reachable_non_generic_provider_local;
-    providers.exported_symbols = exported_symbols_provider_local;
-    providers.upstream_monomorphizations = upstream_monomorphizations_provider;
-    providers.is_unreachable_local_definition = is_unreachable_local_definition_provider;
-}
-
-pub fn provide_extern(providers: &mut Providers) {
-    providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern;
-    providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider;
-}
-
-fn symbol_export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel {
-    // We export anything that's not mangled at the "C" layer as it probably has
-    // to do with ABI concerns. We do not, however, apply such treatment to
-    // special symbols in the standard library for various plumbing between
-    // core/std/allocators/etc. For example symbols used to hook up allocation
-    // are not considered for export
-    let codegen_fn_attrs = tcx.codegen_fn_attrs(sym_def_id);
-    let is_extern = codegen_fn_attrs.contains_extern_indicator();
-    let std_internal =
-        codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
-
-    if is_extern && !std_internal {
-        SymbolExportLevel::C
-    } else {
-        SymbolExportLevel::Rust
-    }
-}
diff --git a/src/librustc_codegen_llvm/back/wasm.rs b/src/librustc_codegen_llvm/back/wasm.rs
index f37854b7bca..7101255173c 100644
--- a/src/librustc_codegen_llvm/back/wasm.rs
+++ b/src/librustc_codegen_llvm/back/wasm.rs
@@ -42,7 +42,7 @@ const WASM_EXTERNAL_KIND_GLOBAL: u8 = 3;
 /// https://github.com/llvm-mirror/llvm/commit/0f32e1365, although support still
 /// needs to be added, tracked at https://bugs.llvm.org/show_bug.cgi?id=37168
 pub fn rewrite_imports(path: &Path, import_map: &FxHashMap<String, String>) {
-    if import_map.len() == 0 {
+    if import_map.is_empty() {
         return
     }
 
@@ -127,7 +127,7 @@ impl<'a> Iterator for WasmSections<'a> {
     type Item = (u8, &'a [u8]);
 
     fn next(&mut self) -> Option<(u8, &'a [u8])> {
-        if self.0.data.len() == 0 {
+        if self.0.data.is_empty() {
             return None
         }
 
diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs
index 95281e2445a..8973852caa8 100644
--- a/src/librustc_codegen_llvm/back/write.rs
+++ b/src/librustc_codegen_llvm/back/write.rs
@@ -10,11 +10,8 @@
 
 use attributes;
 use back::bytecode::{self, RLIB_BYTECODE_EXTENSION};
-use back::lto::{self, ModuleBuffer, ThinBuffer, SerializedModule};
+use back::lto::{self, ThinBuffer, SerializedModule};
 use back::link::{self, get_linker, remove};
-use back::command::Command;
-use back::linker::LinkerInfo;
-use back::symbol_export::ExportedSymbols;
 use base;
 use consts;
 use memmap;
@@ -38,6 +35,9 @@ use rustc::util::common::{time_ext, time_depth, set_time_depth, print_time_passe
 use rustc_fs_util::{path2cstr, link_or_copy};
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_data_structures::svh::Svh;
+use rustc_codegen_utils::command::Command;
+use rustc_codegen_utils::linker::LinkerInfo;
+use rustc_codegen_utils::symbol_export::ExportedSymbols;
 use errors::{self, Handler, Level, DiagnosticBuilder, FatalError, DiagnosticId};
 use errors::emitter::{Emitter};
 use syntax::attr;
@@ -64,7 +64,7 @@ use std::time::Instant;
 use std::thread;
 use libc::{c_uint, c_void, c_char, size_t};
 
-pub const RELOC_MODEL_ARGS : [(&'static str, llvm::RelocMode); 7] = [
+pub const RELOC_MODEL_ARGS : [(&str, llvm::RelocMode); 7] = [
     ("pic", llvm::RelocMode::PIC),
     ("static", llvm::RelocMode::Static),
     ("default", llvm::RelocMode::Default),
@@ -81,7 +81,7 @@ pub const CODE_GEN_MODEL_ARGS: &[(&str, llvm::CodeModel)] = &[
     ("large", llvm::CodeModel::Large),
 ];
 
-pub const TLS_MODEL_ARGS : [(&'static str, llvm::ThreadLocalMode); 4] = [
+pub const TLS_MODEL_ARGS : [(&str, llvm::ThreadLocalMode); 4] = [
     ("global-dynamic", llvm::ThreadLocalMode::GeneralDynamic),
     ("local-dynamic", llvm::ThreadLocalMode::LocalDynamic),
     ("initial-exec", llvm::ThreadLocalMode::InitialExec),
@@ -90,7 +90,7 @@ pub const TLS_MODEL_ARGS : [(&'static str, llvm::ThreadLocalMode); 4] = [
 
 const PRE_THIN_LTO_BC_EXT: &str = "pre-thin-lto.bc";
 
-pub fn llvm_err(handler: &errors::Handler, msg: String) -> FatalError {
+pub fn llvm_err(handler: &errors::Handler, msg: &str) -> FatalError {
     match llvm::last_error() {
         Some(err) => handler.fatal(&format!("{}: {}", msg, err)),
         None => handler.fatal(&msg),
@@ -106,11 +106,10 @@ pub fn write_output_file(
         file_type: llvm::FileType) -> Result<(), FatalError> {
     unsafe {
         let output_c = path2cstr(output);
-        let result = llvm::LLVMRustWriteOutputFile(
-                target, pm, m, output_c.as_ptr(), file_type);
+        let result = llvm::LLVMRustWriteOutputFile(target, pm, m, output_c.as_ptr(), file_type);
         if result.into_result().is_err() {
             let msg = format!("could not write output to {}", output.display());
-            Err(llvm_err(handler, msg))
+            Err(llvm_err(handler, &msg))
         } else {
             Ok(())
         }
@@ -140,7 +139,7 @@ pub fn create_target_machine(
     find_features: bool,
 ) -> &'static mut llvm::TargetMachine {
     target_machine_factory(sess, find_features)().unwrap_or_else(|err| {
-        llvm_err(sess.diagnostic(), err).raise()
+        llvm_err(sess.diagnostic(), &err).raise()
     })
 }
 
@@ -337,6 +336,11 @@ impl ModuleConfig {
         self.merge_functions = sess.opts.optimize == config::OptLevel::Default ||
                                sess.opts.optimize == config::OptLevel::Aggressive;
     }
+
+    pub fn bitcode_needed(&self) -> bool {
+        self.emit_bc || self.obj_is_bitcode
+            || self.emit_bc_compressed || self.embed_bitcode
+    }
 }
 
 /// Assembler name and command used by codegen when no_integrated_as is enabled
@@ -451,7 +455,7 @@ impl<'a> Drop for DiagnosticHandlers<'a> {
 unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext,
                                                msg: &'b str,
                                                cookie: c_uint) {
-    cgcx.diag_emitter.inline_asm_error(cookie as u32, msg.to_string());
+    cgcx.diag_emitter.inline_asm_error(cookie as u32, msg.to_owned());
 }
 
 unsafe extern "C" fn inline_asm_handler(diag: &SMDiagnostic,
@@ -564,8 +568,7 @@ unsafe fn optimize(cgcx: &CodegenContext,
             // Some options cause LLVM bitcode to be emitted, which uses ThinLTOBuffers, so we need
             // to make sure we run LLVM's NameAnonGlobals pass when emitting bitcode; otherwise
             // we'll get errors in LLVM.
-            let using_thin_buffers = llvm::LLVMRustThinLTOAvailable() && (config.emit_bc
-                || config.obj_is_bitcode || config.emit_bc_compressed || config.embed_bitcode);
+            let using_thin_buffers = config.bitcode_needed();
             let mut have_name_anon_globals_pass = false;
             if !config.no_prepopulate_passes {
                 llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
@@ -586,8 +589,7 @@ unsafe fn optimize(cgcx: &CodegenContext,
 
             for pass in &config.passes {
                 if !addpass(pass) {
-                    diag_handler.warn(&format!("unknown pass `{}`, ignoring",
-                                            pass));
+                    diag_handler.warn(&format!("unknown pass `{}`, ignoring", pass));
                 }
                 if pass == "name-anon-globals" {
                     have_name_anon_globals_pass = true;
@@ -597,8 +599,8 @@ unsafe fn optimize(cgcx: &CodegenContext,
             for pass in &cgcx.plugin_passes {
                 if !addpass(pass) {
                     diag_handler.err(&format!("a plugin asked for LLVM pass \
-                                            `{}` but LLVM does not \
-                                            recognize it", pass));
+                                               `{}` but LLVM does not \
+                                               recognize it", pass));
                 }
                 if pass == "name-anon-globals" {
                     have_name_anon_globals_pass = true;
@@ -609,12 +611,12 @@ unsafe fn optimize(cgcx: &CodegenContext,
                 // As described above, this will probably cause an error in LLVM
                 if config.no_prepopulate_passes {
                     diag_handler.err("The current compilation is going to use thin LTO buffers \
-                                     without running LLVM's NameAnonGlobals pass. \
-                                     This will likely cause errors in LLVM. Consider adding \
-                                     -C passes=name-anon-globals to the compiler command line.");
+                                      without running LLVM's NameAnonGlobals pass. \
+                                      This will likely cause errors in LLVM. Consider adding \
+                                      -C passes=name-anon-globals to the compiler command line.");
                 } else {
                     bug!("We are using thin LTO buffers without running the NameAnonGlobals pass. \
-                         This will likely cause errors in LLVM and should never happen.");
+                          This will likely cause errors in LLVM and should never happen.");
                 }
             }
         }
@@ -700,9 +702,9 @@ unsafe fn codegen(cgcx: &CodegenContext,
         // escape the closure itself, and the manager should only be
         // used once.
         unsafe fn with_codegen<'ll, F, R>(tm: &'ll llvm::TargetMachine,
-                                    llmod: &'ll llvm::Module,
-                                    no_builtins: bool,
-                                    f: F) -> R
+                                          llmod: &'ll llvm::Module,
+                                          no_builtins: bool,
+                                          f: F) -> R
             where F: FnOnce(&'ll mut PassManager<'ll>) -> R,
         {
             let cpm = llvm::LLVMCreatePassManager();
@@ -729,15 +731,8 @@ unsafe fn codegen(cgcx: &CodegenContext,
 
 
         if write_bc || config.emit_bc_compressed || config.embed_bitcode {
-            let thin;
-            let old;
-            let data = if llvm::LLVMRustThinLTOAvailable() {
-                thin = ThinBuffer::new(llmod);
-                thin.data()
-            } else {
-                old = ModuleBuffer::new(llmod);
-                old.data()
-            };
+            let thin = ThinBuffer::new(llmod);
+            let data = thin.data();
             timeline.record("make-bc");
 
             if write_bc {
@@ -821,7 +816,7 @@ unsafe fn codegen(cgcx: &CodegenContext,
                 };
                 with_codegen(tm, llmod, config.no_builtins, |cpm| {
                     write_output_file(diag_handler, tm, cpm, llmod, &path,
-                                    llvm::FileType::AssemblyFile)
+                                      llvm::FileType::AssemblyFile)
                 })?;
                 timeline.record("asm");
             }
@@ -829,7 +824,7 @@ unsafe fn codegen(cgcx: &CodegenContext,
             if write_obj {
                 with_codegen(tm, llmod, config.no_builtins, |cpm| {
                     write_output_file(diag_handler, tm, cpm, llmod, &obj_out,
-                                    llvm::FileType::ObjectFile)
+                                      llvm::FileType::ObjectFile)
                 })?;
                 timeline.record("obj");
             } else if asm_to_obj {
@@ -950,11 +945,11 @@ fn need_pre_thin_lto_bitcode_for_incr_comp(sess: &Session) -> bool {
 }
 
 pub fn start_async_codegen(tcx: TyCtxt,
-                               time_graph: Option<TimeGraph>,
-                               metadata: EncodedMetadata,
-                               coordinator_receive: Receiver<Box<dyn Any + Send>>,
-                               total_cgus: usize)
-                               -> OngoingCodegen {
+                           time_graph: Option<TimeGraph>,
+                           metadata: EncodedMetadata,
+                           coordinator_receive: Receiver<Box<dyn Any + Send>>,
+                           total_cgus: usize)
+                           -> OngoingCodegen {
     let sess = tcx.sess;
     let crate_name = tcx.crate_name(LOCAL_CRATE);
     let crate_hash = tcx.crate_hash(LOCAL_CRATE);
@@ -1119,7 +1114,8 @@ fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
         }
 
         if let Some((id, product)) =
-                copy_cgu_workproducts_to_incr_comp_cache_dir(sess, &module.name, &files) {
+            copy_cgu_workproducts_to_incr_comp_cache_dir(sess, &module.name, &files)
+        {
             work_products.insert(id, product);
         }
     }
@@ -1385,12 +1381,8 @@ fn execute_optimize_work_item(cgcx: &CodegenContext,
         // builds we don't actually want to LTO the allocator modules if
         // it shows up. This is due to various linker shenanigans that
         // we'll encounter later.
-        //
-        // Additionally here's where we also factor in the current LLVM
-        // version. If it doesn't support ThinLTO we skip this.
         Lto::ThinLocal => {
-            module.kind != ModuleKind::Allocator &&
-                unsafe { llvm::LLVMRustThinLTOAvailable() }
+            module.kind != ModuleKind::Allocator
         }
     };
 
@@ -1448,15 +1440,12 @@ fn execute_copy_from_cache_work_item(cgcx: &CodegenContext,
                module.name,
                source_file,
                obj_out.display());
-        match link_or_copy(&source_file, &obj_out) {
-            Ok(_) => { }
-            Err(err) => {
-                let diag_handler = cgcx.create_diag_handler();
-                diag_handler.err(&format!("unable to copy {} to {}: {}",
-                                          source_file.display(),
-                                          obj_out.display(),
-                                          err));
-            }
+        if let Err(err) = link_or_copy(&source_file, &obj_out) {
+            let diag_handler = cgcx.create_diag_handler();
+            diag_handler.err(&format!("unable to copy {} to {}: {}",
+                                      source_file.display(),
+                                      obj_out.display(),
+                                      err));
         }
     }
 
@@ -1508,6 +1497,7 @@ enum Message {
     },
     CodegenComplete,
     CodegenItem,
+    CodegenAborted,
 }
 
 struct Diagnostic {
@@ -1540,7 +1530,7 @@ fn start_executing_work(tcx: TyCtxt,
 
     // Compute the set of symbols we need to retain when doing LTO (if we need to)
     let exported_symbols = {
-        let mut exported_symbols = FxHashMap();
+        let mut exported_symbols = FxHashMap::default();
 
         let copy_symbols = |cnum| {
             let symbols = tcx.exported_symbols(cnum)
@@ -1590,10 +1580,8 @@ fn start_executing_work(tcx: TyCtxt,
 
         let (name, mut cmd) = get_linker(sess, &linker, flavor);
         cmd.args(&sess.target.target.options.asm_args);
-        Some(Arc::new(AssemblerCommand {
-            name,
-            cmd,
-        }))
+
+        Some(Arc::new(AssemblerCommand { name, cmd }))
     } else {
         None
     };
@@ -1788,6 +1776,7 @@ fn start_executing_work(tcx: TyCtxt,
         let mut needs_lto = Vec::new();
         let mut lto_import_only_modules = Vec::new();
         let mut started_lto = false;
+        let mut codegen_aborted = false;
 
         // This flag tracks whether all items have gone through codegens
         let mut codegen_done = false;
@@ -1805,13 +1794,19 @@ fn start_executing_work(tcx: TyCtxt,
         let mut llvm_start_time = None;
 
         // Run the message loop while there's still anything that needs message
-        // processing:
+        // processing. Note that as soon as codegen is aborted we simply want to
+        // wait for all existing work to finish, so many of the conditions here
+        // only apply if codegen hasn't been aborted as they represent pending
+        // work to be done.
         while !codegen_done ||
-              work_items.len() > 0 ||
               running > 0 ||
-              needs_lto.len() > 0 ||
-              lto_import_only_modules.len() > 0 ||
-              main_thread_worker_state != MainThreadWorkerState::Idle {
+              (!codegen_aborted && (
+                  work_items.len() > 0 ||
+                  needs_lto.len() > 0 ||
+                  lto_import_only_modules.len() > 0 ||
+                  main_thread_worker_state != MainThreadWorkerState::Idle
+              ))
+        {
 
             // While there are still CGUs to be codegened, the coordinator has
             // to decide how to utilize the compiler processes implicit Token:
@@ -1840,6 +1835,9 @@ fn start_executing_work(tcx: TyCtxt,
                         spawn_work(cgcx, item);
                     }
                 }
+            } else if codegen_aborted {
+                // don't queue up any more work if codegen was aborted, we're
+                // just waiting for our existing children to finish
             } else {
                 // If we've finished everything related to normal codegen
                 // then it must be the case that we've got some LTO work to do.
@@ -1904,7 +1902,7 @@ fn start_executing_work(tcx: TyCtxt,
 
             // Spin up what work we can, only doing this while we've got available
             // parallelism slots and work left to spawn.
-            while work_items.len() > 0 && running < tokens.len() {
+            while !codegen_aborted && work_items.len() > 0 && running < tokens.len() {
                 let (item, _) = work_items.pop().unwrap();
 
                 maybe_start_llvm_timer(cgcx.config(item.module_kind()),
@@ -1969,6 +1967,7 @@ fn start_executing_work(tcx: TyCtxt,
                     if !cgcx.opts.debugging_opts.no_parallel_llvm {
                         helper.request_token();
                     }
+                    assert!(!codegen_aborted);
                     assert_eq!(main_thread_worker_state,
                                MainThreadWorkerState::Codegenning);
                     main_thread_worker_state = MainThreadWorkerState::Idle;
@@ -1976,11 +1975,26 @@ fn start_executing_work(tcx: TyCtxt,
 
                 Message::CodegenComplete => {
                     codegen_done = true;
+                    assert!(!codegen_aborted);
                     assert_eq!(main_thread_worker_state,
                                MainThreadWorkerState::Codegenning);
                     main_thread_worker_state = MainThreadWorkerState::Idle;
                 }
 
+                // If codegen is aborted that means translation was aborted due
+                // to some normal-ish compiler error. In this situation we want
+                // to exit as soon as possible, but we want to make sure all
+                // existing work has finished. Flag codegen as being done, and
+                // then conditions above will ensure no more work is spawned but
+                // we'll keep executing this loop until `running` hits 0.
+                Message::CodegenAborted => {
+                    assert!(!codegen_aborted);
+                    codegen_done = true;
+                    codegen_aborted = true;
+                    assert_eq!(main_thread_worker_state,
+                               MainThreadWorkerState::Codegenning);
+                }
+
                 // If a thread exits successfully then we drop a token associated
                 // with that worker and update our `running` count. We may later
                 // re-acquire a token to continue running more work. We may also not
@@ -2166,9 +2180,9 @@ pub fn run_assembler(cgcx: &CodegenContext, handler: &Handler, assembly: &Path,
                 handler.struct_err(&format!("linking with `{}` failed: {}",
                                             pname.display(),
                                             prog.status))
-                    .note(&format!("{:?}", &cmd))
-                    .note(str::from_utf8(&note[..]).unwrap())
-                    .emit();
+                       .note(&format!("{:?}", &cmd))
+                       .note(str::from_utf8(&note[..]).unwrap())
+                       .emit();
                 handler.abort_if_errors();
             }
         },
@@ -2430,8 +2444,8 @@ impl OngoingCodegen {
     }
 
     pub(crate) fn submit_pre_codegened_module_to_llvm(&self,
-                                                       tcx: TyCtxt,
-                                                       module: ModuleCodegen) {
+                                                      tcx: TyCtxt,
+                                                      module: ModuleCodegen) {
         self.wait_for_signal_to_codegen_item();
         self.check_for_errors(tcx.sess);
 
@@ -2446,6 +2460,19 @@ impl OngoingCodegen {
         drop(self.coordinator_send.send(Box::new(Message::CodegenComplete)));
     }
 
+    /// Consume this context indicating that codegen was entirely aborted, and
+    /// we need to exit as quickly as possible.
+    ///
+    /// This method blocks the current thread until all worker threads have
+    /// finished, and all worker threads should have exited or be real close to
+    /// exiting at this point.
+    pub fn codegen_aborted(self) {
+        // Signal to the coordinator it should spawn no more work and start
+        // shutdown.
+        drop(self.coordinator_send.send(Box::new(Message::CodegenAborted)));
+        drop(self.future.join());
+    }
+
     pub fn check_for_errors(&self, sess: &Session) {
         self.shared_emitter_main.check(sess, false);
     }
@@ -2464,6 +2491,11 @@ impl OngoingCodegen {
     }
 }
 
+// impl Drop for OngoingCodegen {
+//     fn drop(&mut self) {
+//     }
+// }
+
 pub(crate) fn submit_codegened_module_to_llvm(tcx: TyCtxt,
                                               module: ModuleCodegen,
                                               cost: u64) {
diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs
index c814ab4ab67..821b074cd68 100644
--- a/src/librustc_codegen_llvm/base.rs
+++ b/src/librustc_codegen_llvm/base.rs
@@ -39,7 +39,7 @@ use rustc::middle::weak_lang_items;
 use rustc::mir::mono::{Linkage, Visibility, Stats, CodegenUnitNameBuilder};
 use rustc::middle::cstore::{EncodedMetadata};
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::layout::{self, Align, TyLayout, LayoutOf};
+use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, VariantIdx};
 use rustc::ty::query::Providers;
 use rustc::middle::cstore::{self, LinkagePreference};
 use rustc::middle::exported_symbols;
@@ -53,10 +53,9 @@ use mir::place::PlaceRef;
 use attributes;
 use builder::{Builder, MemFlags};
 use callee;
-use common::{C_bool, C_bytes_in_context, C_i32, C_usize};
-use rustc_mir::monomorphize::collector::{self, MonoItemCollectionMode};
+use common::{C_bool, C_bytes_in_context, C_usize};
 use rustc_mir::monomorphize::item::DefPathBasedNames;
-use common::{self, C_struct_in_context, C_array, val_ty};
+use common::{C_struct_in_context, C_array, val_ty};
 use consts;
 use context::CodegenCx;
 use debuginfo;
@@ -64,24 +63,24 @@ use declare;
 use meth;
 use mir;
 use monomorphize::Instance;
-use monomorphize::partitioning::{self, PartitioningStrategy, CodegenUnit, CodegenUnitExt};
+use monomorphize::partitioning::{CodegenUnit, CodegenUnitExt};
 use rustc_codegen_utils::symbol_names_test;
 use time_graph;
-use mono_item::{MonoItem, BaseMonoItemExt, MonoItemExt};
+use mono_item::{MonoItem, MonoItemExt};
 use type_::Type;
 use type_of::LayoutLlvmExt;
-use rustc::util::nodemap::{FxHashMap, FxHashSet, DefIdSet};
+use rustc::util::nodemap::FxHashMap;
 use CrateInfo;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::indexed_vec::Idx;
 
 use std::any::Any;
-use std::ffi::CString;
-use std::sync::Arc;
-use std::time::{Instant, Duration};
-use std::i32;
 use std::cmp;
+use std::ffi::CString;
+use std::ops::{Deref, DerefMut};
 use std::sync::mpsc;
+use std::time::{Instant, Duration};
 use syntax_pos::Span;
 use syntax_pos::symbol::InternedString;
 use syntax::attr;
@@ -311,7 +310,7 @@ pub fn coerce_unsized_into(
         (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
             assert_eq!(def_a, def_b);
 
-            for i in 0..def_a.variants[0].fields.len() {
+            for i in 0..def_a.variants[VariantIdx::new(0)].fields.len() {
                 let src_f = src.project_field(bx, i);
                 let dst_f = dst.project_field(bx, i);
 
@@ -320,8 +319,8 @@ pub fn coerce_unsized_into(
                 }
 
                 if src_f.layout.ty == dst_f.layout.ty {
-                    memcpy_ty(bx, dst_f.llval, src_f.llval, src_f.layout,
-                              src_f.align.min(dst_f.align), MemFlags::empty());
+                    memcpy_ty(bx, dst_f.llval, dst_f.align, src_f.llval, src_f.align,
+                              src_f.layout, MemFlags::empty());
                 } else {
                     coerce_unsized_into(bx, src_f, dst_f);
                 }
@@ -421,36 +420,34 @@ pub fn to_immediate_scalar(
 pub fn call_memcpy(
     bx: &Builder<'_, 'll, '_>,
     dst: &'ll Value,
+    dst_align: Align,
     src: &'ll Value,
+    src_align: Align,
     n_bytes: &'ll Value,
-    align: Align,
     flags: MemFlags,
 ) {
     if flags.contains(MemFlags::NONTEMPORAL) {
         // HACK(nox): This is inefficient but there is no nontemporal memcpy.
-        let val = bx.load(src, align);
+        let val = bx.load(src, src_align);
         let ptr = bx.pointercast(dst, val_ty(val).ptr_to());
-        bx.store_with_flags(val, ptr, align, flags);
+        bx.store_with_flags(val, ptr, dst_align, flags);
         return;
     }
     let cx = bx.cx;
-    let ptr_width = &cx.sess().target.target.target_pointer_width;
-    let key = format!("llvm.memcpy.p0i8.p0i8.i{}", ptr_width);
-    let memcpy = cx.get_intrinsic(&key);
     let src_ptr = bx.pointercast(src, Type::i8p(cx));
     let dst_ptr = bx.pointercast(dst, Type::i8p(cx));
     let size = bx.intcast(n_bytes, cx.isize_ty, false);
-    let align = C_i32(cx, align.abi() as i32);
-    let volatile = C_bool(cx, flags.contains(MemFlags::VOLATILE));
-    bx.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None);
+    let volatile = flags.contains(MemFlags::VOLATILE);
+    bx.memcpy(dst_ptr, dst_align.abi(), src_ptr, src_align.abi(), size, volatile);
 }
 
 pub fn memcpy_ty(
     bx: &Builder<'_, 'll, 'tcx>,
     dst: &'ll Value,
+    dst_align: Align,
     src: &'ll Value,
+    src_align: Align,
     layout: TyLayout<'tcx>,
-    align: Align,
     flags: MemFlags,
 ) {
     let size = layout.size.bytes();
@@ -458,7 +455,7 @@ pub fn memcpy_ty(
         return;
     }
 
-    call_memcpy(bx, dst, src, C_usize(bx.cx, size), align, flags);
+    call_memcpy(bx, dst, dst_align, src, src_align, C_usize(bx.cx, size), flags);
 }
 
 pub fn call_memset(
@@ -491,8 +488,7 @@ pub fn codegen_instance<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, instance: Instance<'
     // release builds.
     info!("codegen_instance({})", instance);
 
-    let fn_ty = instance.ty(cx.tcx);
-    let sig = common::ty_fn_sig(cx, fn_ty);
+    let sig = instance.fn_sig(cx.tcx);
     let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
 
     let lldecl = cx.instances.borrow().get(&instance).cloned().unwrap_or_else(||
@@ -558,7 +554,7 @@ fn maybe_create_entry_wrapper(cx: &CodegenCx) {
         // regions must appear in the argument
         // listing.
         let main_ret_ty = cx.tcx.erase_regions(
-            &main_ret_ty.no_late_bound_regions().unwrap(),
+            &main_ret_ty.no_bound_vars().unwrap(),
         );
 
         if declare::get_defined_value(cx, "main").is_some() {
@@ -739,19 +735,6 @@ pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 {
     check_for_rustc_errors_attr(tcx);
 
-    if let Some(true) = tcx.sess.opts.debugging_opts.thinlto {
-        if unsafe { !llvm::LLVMRustThinLTOAvailable() } {
-            tcx.sess.fatal("this compiler's LLVM does not support ThinLTO");
-        }
-    }
-
-    if (tcx.sess.opts.debugging_opts.pgo_gen.is_some() ||
-        !tcx.sess.opts.debugging_opts.pgo_use.is_empty()) &&
-        unsafe { !llvm::LLVMRustPGOAvailable() }
-    {
-        tcx.sess.fatal("this compiler's LLVM does not support PGO");
-    }
-
     let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
 
     // Codegen the metadata.
@@ -784,7 +767,7 @@ pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
        !tcx.sess.opts.output_types.should_codegen() {
         let ongoing_codegen = write::start_async_codegen(
             tcx,
-            time_graph.clone(),
+            time_graph,
             metadata,
             rx,
             1);
@@ -821,6 +804,7 @@ pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         metadata,
         rx,
         codegen_units.len());
+    let ongoing_codegen = AbortCodegenOnDrop(Some(ongoing_codegen));
 
     // Codegen an allocator shim, if necessary.
     //
@@ -950,139 +934,64 @@ pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     ongoing_codegen.check_for_errors(tcx.sess);
 
     assert_and_save_dep_graph(tcx);
-    ongoing_codegen
+    ongoing_codegen.into_inner()
 }
 
-fn assert_and_save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    time(tcx.sess,
-         "assert dep graph",
-         || rustc_incremental::assert_dep_graph(tcx));
-
-    time(tcx.sess,
-         "serialize dep graph",
-         || rustc_incremental::save_dep_graph(tcx));
+/// A curious wrapper structure whose only purpose is to call `codegen_aborted`
+/// when it's dropped abnormally.
+///
+/// In the process of working on rust-lang/rust#55238 a mysterious segfault was
+/// stumbled upon. The segfault was never reproduced locally, but it was
+/// suspected to be releated to the fact that codegen worker threads were
+/// sticking around by the time the main thread was exiting, causing issues.
+///
+/// This structure is an attempt to fix that issue where the `codegen_aborted`
+/// message will block until all workers have finished. This should ensure that
+/// even if the main codegen thread panics we'll wait for pending work to
+/// complete before returning from the main thread, hopefully avoiding
+/// segfaults.
+///
+/// If you see this comment in the code, then it means that this workaround
+/// worked! We may yet one day track down the mysterious cause of that
+/// segfault...
+struct AbortCodegenOnDrop(Option<OngoingCodegen>);
+
+impl AbortCodegenOnDrop {
+    fn into_inner(mut self) -> OngoingCodegen {
+        self.0.take().unwrap()
+    }
 }
 
-fn collect_and_partition_mono_items<'a, 'tcx>(
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    cnum: CrateNum,
-) -> (Arc<DefIdSet>, Arc<Vec<Arc<CodegenUnit<'tcx>>>>)
-{
-    assert_eq!(cnum, LOCAL_CRATE);
-
-    let collection_mode = match tcx.sess.opts.debugging_opts.print_mono_items {
-        Some(ref s) => {
-            let mode_string = s.to_lowercase();
-            let mode_string = mode_string.trim();
-            if mode_string == "eager" {
-                MonoItemCollectionMode::Eager
-            } else {
-                if mode_string != "lazy" {
-                    let message = format!("Unknown codegen-item collection mode '{}'. \
-                                           Falling back to 'lazy' mode.",
-                                          mode_string);
-                    tcx.sess.warn(&message);
-                }
-
-                MonoItemCollectionMode::Lazy
-            }
-        }
-        None => {
-            if tcx.sess.opts.cg.link_dead_code {
-                MonoItemCollectionMode::Eager
-            } else {
-                MonoItemCollectionMode::Lazy
-            }
-        }
-    };
-
-    let (items, inlining_map) =
-        time(tcx.sess, "monomorphization collection", || {
-            collector::collect_crate_mono_items(tcx, collection_mode)
-    });
-
-    tcx.sess.abort_if_errors();
-
-    ::rustc_mir::monomorphize::assert_symbols_are_distinct(tcx, items.iter());
-
-    let strategy = if tcx.sess.opts.incremental.is_some() {
-        PartitioningStrategy::PerModule
-    } else {
-        PartitioningStrategy::FixedUnitCount(tcx.sess.codegen_units())
-    };
-
-    let codegen_units = time(tcx.sess, "codegen unit partitioning", || {
-        partitioning::partition(tcx,
-                                items.iter().cloned(),
-                                strategy,
-                                &inlining_map)
-            .into_iter()
-            .map(Arc::new)
-            .collect::<Vec<_>>()
-    });
-
-    let mono_items: DefIdSet = items.iter().filter_map(|mono_item| {
-        match *mono_item {
-            MonoItem::Fn(ref instance) => Some(instance.def_id()),
-            MonoItem::Static(def_id) => Some(def_id),
-            _ => None,
-        }
-    }).collect();
-
-    if tcx.sess.opts.debugging_opts.print_mono_items.is_some() {
-        let mut item_to_cgus: FxHashMap<_, Vec<_>> = FxHashMap();
-
-        for cgu in &codegen_units {
-            for (&mono_item, &linkage) in cgu.items() {
-                item_to_cgus.entry(mono_item)
-                            .or_default()
-                            .push((cgu.name().clone(), linkage));
-            }
-        }
+impl Deref for AbortCodegenOnDrop {
+    type Target = OngoingCodegen;
 
-        let mut item_keys: Vec<_> = items
-            .iter()
-            .map(|i| {
-                let mut output = i.to_string(tcx);
-                output.push_str(" @@");
-                let mut empty = Vec::new();
-                let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty);
-                cgus.as_mut_slice().sort_by_key(|&(ref name, _)| name.clone());
-                cgus.dedup();
-                for &(ref cgu_name, (linkage, _)) in cgus.iter() {
-                    output.push_str(" ");
-                    output.push_str(&cgu_name.as_str());
-
-                    let linkage_abbrev = match linkage {
-                        Linkage::External => "External",
-                        Linkage::AvailableExternally => "Available",
-                        Linkage::LinkOnceAny => "OnceAny",
-                        Linkage::LinkOnceODR => "OnceODR",
-                        Linkage::WeakAny => "WeakAny",
-                        Linkage::WeakODR => "WeakODR",
-                        Linkage::Appending => "Appending",
-                        Linkage::Internal => "Internal",
-                        Linkage::Private => "Private",
-                        Linkage::ExternalWeak => "ExternalWeak",
-                        Linkage::Common => "Common",
-                    };
-
-                    output.push_str("[");
-                    output.push_str(linkage_abbrev);
-                    output.push_str("]");
-                }
-                output
-            })
-            .collect();
+    fn deref(&self) -> &OngoingCodegen {
+        self.0.as_ref().unwrap()
+    }
+}
 
-        item_keys.sort();
+impl DerefMut for AbortCodegenOnDrop {
+    fn deref_mut(&mut self) -> &mut OngoingCodegen {
+        self.0.as_mut().unwrap()
+    }
+}
 
-        for item in item_keys {
-            println!("MONO_ITEM {}", item);
+impl Drop for AbortCodegenOnDrop {
+    fn drop(&mut self) {
+        if let Some(codegen) = self.0.take() {
+            codegen.codegen_aborted();
         }
     }
+}
 
-    (Arc::new(mono_items), Arc::new(codegen_units))
+fn assert_and_save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+    time(tcx.sess,
+         "assert dep graph",
+         || rustc_incremental::assert_dep_graph(tcx));
+
+    time(tcx.sess,
+         "serialize dep graph",
+         || rustc_incremental::save_dep_graph(tcx));
 }
 
 impl CrateInfo {
@@ -1092,17 +1001,17 @@ impl CrateInfo {
             compiler_builtins: None,
             profiler_runtime: None,
             sanitizer_runtime: None,
-            is_no_builtins: FxHashSet(),
-            native_libraries: FxHashMap(),
+            is_no_builtins: Default::default(),
+            native_libraries: Default::default(),
             used_libraries: tcx.native_libraries(LOCAL_CRATE),
             link_args: tcx.link_args(LOCAL_CRATE),
-            crate_name: FxHashMap(),
+            crate_name: Default::default(),
             used_crates_dynamic: cstore::used_crates(tcx, LinkagePreference::RequireDynamic),
             used_crates_static: cstore::used_crates(tcx, LinkagePreference::RequireStatic),
-            used_crate_source: FxHashMap(),
-            wasm_imports: FxHashMap(),
-            lang_item_to_crate: FxHashMap(),
-            missing_lang_items: FxHashMap(),
+            used_crate_source: Default::default(),
+            wasm_imports: Default::default(),
+            lang_item_to_crate: Default::default(),
+            missing_lang_items: Default::default(),
         };
         let lang_items = tcx.lang_items();
 
@@ -1174,12 +1083,6 @@ impl CrateInfo {
     }
 }
 
-fn is_codegened_item(tcx: TyCtxt, id: DefId) -> bool {
-    let (all_mono_items, _) =
-        tcx.collect_and_partition_mono_items(LOCAL_CRATE);
-    all_mono_items.contains(&id)
-}
-
 fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                   cgu_name: InternedString)
                                   -> Stats {
@@ -1270,24 +1173,7 @@ fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
-pub fn provide(providers: &mut Providers) {
-    providers.collect_and_partition_mono_items =
-        collect_and_partition_mono_items;
-
-    providers.is_codegened_item = is_codegened_item;
-
-    providers.codegen_unit = |tcx, name| {
-        let (_, all) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
-        all.iter()
-            .find(|cgu| *cgu.name() == name)
-            .cloned()
-            .unwrap_or_else(|| panic!("failed to find cgu with name {:?}", name))
-    };
-
-    provide_extern(providers);
-}
-
-pub fn provide_extern(providers: &mut Providers) {
+pub fn provide_both(providers: &mut Providers) {
     providers.dllimport_foreign_items = |tcx, krate| {
         let module_map = tcx.foreign_modules(krate);
         let module_map = module_map.iter()
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index 169bd9a8466..9db4015013e 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -482,14 +482,12 @@ impl Builder<'a, 'll, 'tcx> {
         }
     }
 
-    pub fn atomic_load(&self, ptr: &'ll Value, order: AtomicOrdering, align: Align) -> &'ll Value {
+    pub fn atomic_load(&self, ptr: &'ll Value, order: AtomicOrdering, size: Size) -> &'ll Value {
         self.count_insn("load.atomic");
         unsafe {
             let load = llvm::LLVMRustBuildAtomicLoad(self.llbuilder, ptr, noname(), order);
-            // FIXME(eddyb) Isn't it UB to use `pref` instead of `abi` here?
-            // However, 64-bit atomic loads on `i686-apple-darwin` appear to
-            // require `___atomic_load` with ABI-alignment, so it's staying.
-            llvm::LLVMSetAlignment(load, align.pref() as c_uint);
+            // LLVM requires the alignment of atomic loads to be at least the size of the type.
+            llvm::LLVMSetAlignment(load, size.bytes() as c_uint);
             load
         }
     }
@@ -564,15 +562,14 @@ impl Builder<'a, 'll, 'tcx> {
     }
 
     pub fn atomic_store(&self, val: &'ll Value, ptr: &'ll Value,
-                        order: AtomicOrdering, align: Align) {
+                        order: AtomicOrdering, size: Size) {
         debug!("Store {:?} -> {:?}", val, ptr);
         self.count_insn("store.atomic");
         let ptr = self.check_store(val, ptr);
         unsafe {
             let store = llvm::LLVMRustBuildAtomicStore(self.llbuilder, val, ptr, order);
-            // FIXME(eddyb) Isn't it UB to use `pref` instead of `abi` here?
-            // Also see `atomic_load` for more context.
-            llvm::LLVMSetAlignment(store, align.pref() as c_uint);
+            // LLVM requires the alignment of atomic stores to be at least the size of the type.
+            llvm::LLVMSetAlignment(store, size.bytes() as c_uint);
         }
     }
 
@@ -761,7 +758,7 @@ impl Builder<'a, 'll, 'tcx> {
                     fty, asm, cons, volatile, alignstack, dia);
                 Some(self.call(v, inputs, None))
             } else {
-                // LLVM has detected an issue with our constaints, bail out
+                // LLVM has detected an issue with our constraints, bail out
                 None
             }
         }
@@ -784,6 +781,24 @@ impl Builder<'a, 'll, 'tcx> {
         }
     }
 
+    pub fn memcpy(&self, dst: &'ll Value, dst_align: u64,
+                  src: &'ll Value, src_align: u64,
+                  size: &'ll Value, is_volatile: bool) -> &'ll Value {
+        unsafe {
+            llvm::LLVMRustBuildMemCpy(self.llbuilder, dst, dst_align as c_uint,
+                                      src, src_align as c_uint, size, is_volatile)
+        }
+    }
+
+    pub fn memmove(&self, dst: &'ll Value, dst_align: u64,
+                  src: &'ll Value, src_align: u64,
+                  size: &'ll Value, is_volatile: bool) -> &'ll Value {
+        unsafe {
+            llvm::LLVMRustBuildMemMove(self.llbuilder, dst, dst_align as c_uint,
+                                      src, src_align as c_uint, size, is_volatile)
+        }
+    }
+
     pub fn minnum(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
         self.count_insn("minnum");
         unsafe {
@@ -859,8 +874,7 @@ impl Builder<'a, 'll, 'tcx> {
             // FIXME: add a non-fast math version once
             // https://bugs.llvm.org/show_bug.cgi?id=36732
             // is fixed.
-            let instr = llvm::LLVMRustBuildVectorReduceFAdd(self.llbuilder, acc, src)
-                .expect("LLVMRustBuildVectorReduceFAdd is not available in LLVM version < 5.0");
+            let instr = llvm::LLVMRustBuildVectorReduceFAdd(self.llbuilder, acc, src);
             llvm::LLVMRustSetHasUnsafeAlgebra(instr);
             instr
         }
@@ -871,66 +885,43 @@ impl Builder<'a, 'll, 'tcx> {
             // FIXME: add a non-fast math version once
             // https://bugs.llvm.org/show_bug.cgi?id=36732
             // is fixed.
-            let instr = llvm::LLVMRustBuildVectorReduceFMul(self.llbuilder, acc, src)
-                .expect("LLVMRustBuildVectorReduceFMul is not available in LLVM version < 5.0");
+            let instr = llvm::LLVMRustBuildVectorReduceFMul(self.llbuilder, acc, src);
             llvm::LLVMRustSetHasUnsafeAlgebra(instr);
             instr
         }
     }
     pub fn vector_reduce_add(&self, src: &'ll Value) -> &'ll Value {
         self.count_insn("vector.reduce.add");
-        unsafe {
-            let instr = llvm::LLVMRustBuildVectorReduceAdd(self.llbuilder, src);
-            instr.expect("LLVMRustBuildVectorReduceAdd is not available in LLVM version < 5.0")
-        }
+        unsafe { llvm::LLVMRustBuildVectorReduceAdd(self.llbuilder, src) }
     }
     pub fn vector_reduce_mul(&self, src: &'ll Value) -> &'ll Value {
         self.count_insn("vector.reduce.mul");
-        unsafe {
-            let instr = llvm::LLVMRustBuildVectorReduceMul(self.llbuilder, src);
-            instr.expect("LLVMRustBuildVectorReduceMul is not available in LLVM version < 5.0")
-        }
+        unsafe { llvm::LLVMRustBuildVectorReduceMul(self.llbuilder, src) }
     }
     pub fn vector_reduce_and(&self, src: &'ll Value) -> &'ll Value {
         self.count_insn("vector.reduce.and");
-        unsafe {
-            let instr = llvm::LLVMRustBuildVectorReduceAnd(self.llbuilder, src);
-            instr.expect("LLVMRustBuildVectorReduceAnd is not available in LLVM version < 5.0")
-        }
+        unsafe { llvm::LLVMRustBuildVectorReduceAnd(self.llbuilder, src) }
     }
     pub fn vector_reduce_or(&self, src: &'ll Value) -> &'ll Value {
         self.count_insn("vector.reduce.or");
-        unsafe {
-            let instr = llvm::LLVMRustBuildVectorReduceOr(self.llbuilder, src);
-            instr.expect("LLVMRustBuildVectorReduceOr is not available in LLVM version < 5.0")
-        }
+        unsafe { llvm::LLVMRustBuildVectorReduceOr(self.llbuilder, src) }
     }
     pub fn vector_reduce_xor(&self, src: &'ll Value) -> &'ll Value {
         self.count_insn("vector.reduce.xor");
-        unsafe {
-            let instr = llvm::LLVMRustBuildVectorReduceXor(self.llbuilder, src);
-            instr.expect("LLVMRustBuildVectorReduceXor is not available in LLVM version < 5.0")
-        }
+        unsafe { llvm::LLVMRustBuildVectorReduceXor(self.llbuilder, src) }
     }
     pub fn vector_reduce_fmin(&self, src: &'ll Value) -> &'ll Value {
         self.count_insn("vector.reduce.fmin");
-        unsafe {
-            let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ false);
-            instr.expect("LLVMRustBuildVectorReduceFMin is not available in LLVM version < 5.0")
-        }
+        unsafe { llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ false) }
     }
     pub fn vector_reduce_fmax(&self, src: &'ll Value) -> &'ll Value {
         self.count_insn("vector.reduce.fmax");
-        unsafe {
-            let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ false);
-            instr.expect("LLVMRustBuildVectorReduceFMax is not available in LLVM version < 5.0")
-        }
+        unsafe { llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ false) }
     }
     pub fn vector_reduce_fmin_fast(&self, src: &'ll Value) -> &'ll Value {
         self.count_insn("vector.reduce.fmin_fast");
         unsafe {
-            let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ true)
-                .expect("LLVMRustBuildVectorReduceFMin is not available in LLVM version < 5.0");
+            let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ true);
             llvm::LLVMRustSetHasUnsafeAlgebra(instr);
             instr
         }
@@ -938,25 +929,18 @@ impl Builder<'a, 'll, 'tcx> {
     pub fn vector_reduce_fmax_fast(&self, src: &'ll Value) -> &'ll Value {
         self.count_insn("vector.reduce.fmax_fast");
         unsafe {
-            let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ true)
-                .expect("LLVMRustBuildVectorReduceFMax is not available in LLVM version < 5.0");
+            let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ true);
             llvm::LLVMRustSetHasUnsafeAlgebra(instr);
             instr
         }
     }
     pub fn vector_reduce_min(&self, src: &'ll Value, is_signed: bool) -> &'ll Value {
         self.count_insn("vector.reduce.min");
-        unsafe {
-            let instr = llvm::LLVMRustBuildVectorReduceMin(self.llbuilder, src, is_signed);
-            instr.expect("LLVMRustBuildVectorReduceMin is not available in LLVM version < 5.0")
-        }
+        unsafe { llvm::LLVMRustBuildVectorReduceMin(self.llbuilder, src, is_signed) }
     }
     pub fn vector_reduce_max(&self, src: &'ll Value, is_signed: bool) -> &'ll Value {
         self.count_insn("vector.reduce.max");
-        unsafe {
-            let instr = llvm::LLVMRustBuildVectorReduceMax(self.llbuilder, src, is_signed);
-            instr.expect("LLVMRustBuildVectorReduceMax is not available in LLVM version < 5.0")
-        }
+        unsafe { llvm::LLVMRustBuildVectorReduceMax(self.llbuilder, src, is_signed) }
     }
 
     pub fn extract_value(&self, agg_val: &'ll Value, idx: u64) -> &'ll Value {
diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs
index 4b4ccb3b600..c8c693257d5 100644
--- a/src/librustc_codegen_llvm/callee.rs
+++ b/src/librustc_codegen_llvm/callee.rs
@@ -44,19 +44,19 @@ pub fn get_fn(
     debug!("get_fn(instance={:?})", instance);
 
     assert!(!instance.substs.needs_infer());
-    assert!(!instance.substs.has_escaping_regions());
+    assert!(!instance.substs.has_escaping_bound_vars());
     assert!(!instance.substs.has_param_types());
 
-    let fn_ty = instance.ty(cx.tcx);
+    let sig = instance.fn_sig(cx.tcx);
     if let Some(&llfn) = cx.instances.borrow().get(&instance) {
         return llfn;
     }
 
     let sym = tcx.symbol_name(instance).as_str();
-    debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym);
+    debug!("get_fn({:?}: {:?}) => {}", instance, sig, sym);
 
     // Create a fn pointer with the substituted signature.
-    let fn_ptr_ty = tcx.mk_fn_ptr(common::ty_fn_sig(cx, fn_ty));
+    let fn_ptr_ty = tcx.mk_fn_ptr(sig);
     let llptrty = cx.layout_of(fn_ptr_ty).llvm_type(cx);
 
     let llfn = if let Some(llfn) = declare::get_declared_value(cx, &sym) {
@@ -91,7 +91,7 @@ pub fn get_fn(
             llfn
         }
     } else {
-        let llfn = declare::declare_fn(cx, &sym, fn_ty);
+        let llfn = declare::declare_fn(cx, &sym, sig);
         assert_eq!(common::val_ty(llfn), llptrty);
         debug!("get_fn: not casting pointer!");
 
@@ -220,3 +220,19 @@ pub fn resolve_and_get_fn(
         ).unwrap()
     )
 }
+
+pub fn resolve_and_get_fn_for_vtable(
+    cx: &CodegenCx<'ll, 'tcx>,
+    def_id: DefId,
+    substs: &'tcx Substs<'tcx>,
+) -> &'ll Value {
+    get_fn(
+        cx,
+        ty::Instance::resolve_for_vtable(
+            cx.tcx,
+            ty::ParamEnv::reveal_all(),
+            def_id,
+            substs
+        ).unwrap()
+    )
+}
diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs
index c08937fa9b9..c9b464fd8f3 100644
--- a/src/librustc_codegen_llvm/common.rs
+++ b/src/librustc_codegen_llvm/common.rs
@@ -30,9 +30,7 @@ use rustc::ty::layout::{HasDataLayout, LayoutOf};
 use rustc::hir;
 
 use libc::{c_uint, c_char};
-use std::iter;
 
-use rustc_target::spec::abi::Abi;
 use syntax::symbol::LocalInternedString;
 use syntax_pos::{Span, DUMMY_SP};
 
@@ -404,52 +402,3 @@ pub fn shift_mask_val(
         _ => bug!("shift_mask_val: expected Integer or Vector, found {:?}", kind),
     }
 }
-
-pub fn ty_fn_sig<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
-                           ty: Ty<'tcx>)
-                           -> ty::PolyFnSig<'tcx>
-{
-    match ty.sty {
-        ty::FnDef(..) |
-        // Shims currently have type FnPtr. Not sure this should remain.
-        ty::FnPtr(_) => ty.fn_sig(cx.tcx),
-        ty::Closure(def_id, substs) => {
-            let tcx = cx.tcx;
-            let sig = substs.closure_sig(def_id, tcx);
-
-            let env_ty = tcx.closure_env_ty(def_id, substs).unwrap();
-            sig.map_bound(|sig| tcx.mk_fn_sig(
-                iter::once(*env_ty.skip_binder()).chain(sig.inputs().iter().cloned()),
-                sig.output(),
-                sig.variadic,
-                sig.unsafety,
-                sig.abi
-            ))
-        }
-        ty::Generator(def_id, substs, _) => {
-            let tcx = cx.tcx;
-            let sig = substs.poly_sig(def_id, cx.tcx);
-
-            let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv);
-            let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty);
-
-            sig.map_bound(|sig| {
-                let state_did = tcx.lang_items().gen_state().unwrap();
-                let state_adt_ref = tcx.adt_def(state_did);
-                let state_substs = tcx.intern_substs(&[
-                    sig.yield_ty.into(),
-                    sig.return_ty.into(),
-                ]);
-                let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
-
-                tcx.mk_fn_sig(iter::once(env_ty),
-                    ret_ty,
-                    false,
-                    hir::Unsafety::Normal,
-                    Abi::Rust
-                )
-            })
-        }
-        _ => bug!("unexpected type {:?} to ty_fn_sig", ty)
-    }
-}
diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs
index e6197423738..d6fd0690715 100644
--- a/src/librustc_codegen_llvm/context.rs
+++ b/src/librustc_codegen_llvm/context.rs
@@ -29,7 +29,7 @@ use rustc_data_structures::small_c_str::SmallCStr;
 use rustc::mir::mono::Stats;
 use rustc::session::config::{self, DebugInfo};
 use rustc::session::Session;
-use rustc::ty::layout::{LayoutError, LayoutOf, Size, TyLayout};
+use rustc::ty::layout::{LayoutError, LayoutOf, Size, TyLayout, VariantIdx};
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::util::nodemap::FxHashMap;
 use rustc_target::spec::{HasTargetSpec, Target};
@@ -87,7 +87,7 @@ pub struct CodegenCx<'a, 'tcx: 'a> {
     /// See http://llvm.org/docs/LangRef.html#the-llvm-used-global-variable for details
     pub used_statics: RefCell<Vec<&'a Value>>,
 
-    pub lltypes: RefCell<FxHashMap<(Ty<'tcx>, Option<usize>), &'a Type>>,
+    pub lltypes: RefCell<FxHashMap<(Ty<'tcx>, Option<VariantIdx>), &'a Type>>,
     pub scalar_lltypes: RefCell<FxHashMap<Ty<'tcx>, &'a Type>>,
     pub pointee_infos: RefCell<FxHashMap<(Ty<'tcx>, Size), Option<PointeeInfo>>>,
     pub isize_ty: &'a Type,
@@ -295,22 +295,22 @@ impl<'a, 'tcx> CodegenCx<'a, 'tcx> {
             llcx,
             stats: RefCell::new(Stats::default()),
             codegen_unit,
-            instances: RefCell::new(FxHashMap()),
-            vtables: RefCell::new(FxHashMap()),
-            const_cstr_cache: RefCell::new(FxHashMap()),
-            const_unsized: RefCell::new(FxHashMap()),
-            const_globals: RefCell::new(FxHashMap()),
+            instances: Default::default(),
+            vtables: Default::default(),
+            const_cstr_cache: Default::default(),
+            const_unsized: Default::default(),
+            const_globals: Default::default(),
             statics_to_rauw: RefCell::new(Vec::new()),
             used_statics: RefCell::new(Vec::new()),
-            lltypes: RefCell::new(FxHashMap()),
-            scalar_lltypes: RefCell::new(FxHashMap()),
-            pointee_infos: RefCell::new(FxHashMap()),
+            lltypes: Default::default(),
+            scalar_lltypes: Default::default(),
+            pointee_infos: Default::default(),
             isize_ty,
             dbg_cx,
             eh_personality: Cell::new(None),
             eh_unwind_resume: Cell::new(None),
             rust_try_fn: Cell::new(None),
-            intrinsics: RefCell::new(FxHashMap()),
+            intrinsics: Default::default(),
             local_gen_sym_counter: Cell::new(0),
         }
     }
@@ -404,15 +404,15 @@ impl<'b, 'tcx> CodegenCx<'b, 'tcx> {
             return llfn;
         }
 
-        let ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig(
+        let sig = ty::Binder::bind(tcx.mk_fn_sig(
             iter::once(tcx.mk_mut_ptr(tcx.types.u8)),
             tcx.types.never,
             false,
             hir::Unsafety::Unsafe,
             Abi::C
-        )));
+        ));
 
-        let llfn = declare::declare_fn(self, "rust_eh_unwind_resume", ty);
+        let llfn = declare::declare_fn(self, "rust_eh_unwind_resume", sig);
         attributes::unwind(llfn, true);
         attributes::apply_target_cpu_attr(self, llfn);
         unwresume.set(Some(llfn));
@@ -446,29 +446,29 @@ impl<'b, 'tcx> CodegenCx<'b, 'tcx> {
     }
 }
 
-impl ty::layout::HasDataLayout for &'a CodegenCx<'ll, 'tcx> {
+impl ty::layout::HasDataLayout for CodegenCx<'ll, 'tcx> {
     fn data_layout(&self) -> &ty::layout::TargetDataLayout {
         &self.tcx.data_layout
     }
 }
 
-impl HasTargetSpec for &'a CodegenCx<'ll, 'tcx> {
+impl HasTargetSpec for CodegenCx<'ll, 'tcx> {
     fn target_spec(&self) -> &Target {
         &self.tcx.sess.target.target
     }
 }
 
-impl ty::layout::HasTyCtxt<'tcx> for &'a CodegenCx<'ll, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
+impl ty::layout::HasTyCtxt<'tcx> for CodegenCx<'ll, 'tcx> {
+    fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
         self.tcx
     }
 }
 
-impl LayoutOf for &'a CodegenCx<'ll, 'tcx> {
+impl LayoutOf for CodegenCx<'ll, 'tcx> {
     type Ty = Ty<'tcx>;
     type TyLayout = TyLayout<'tcx>;
 
-    fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
+    fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout {
         self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty))
             .unwrap_or_else(|e| if let LayoutError::SizeOverflow(_) = e {
                 self.sess().fatal(&e.to_string())
@@ -530,12 +530,6 @@ fn declare_intrinsic(cx: &CodegenCx<'ll, '_>, key: &str) -> Option<&'ll Value> {
     let t_v4f64 = Type::vector(t_f64, 4);
     let t_v8f64 = Type::vector(t_f64, 8);
 
-    ifn!("llvm.memcpy.p0i8.p0i8.i16", fn(i8p, i8p, t_i16, t_i32, i1) -> void);
-    ifn!("llvm.memcpy.p0i8.p0i8.i32", fn(i8p, i8p, t_i32, t_i32, i1) -> void);
-    ifn!("llvm.memcpy.p0i8.p0i8.i64", fn(i8p, i8p, t_i64, t_i32, i1) -> void);
-    ifn!("llvm.memmove.p0i8.p0i8.i16", fn(i8p, i8p, t_i16, t_i32, i1) -> void);
-    ifn!("llvm.memmove.p0i8.p0i8.i32", fn(i8p, i8p, t_i32, t_i32, i1) -> void);
-    ifn!("llvm.memmove.p0i8.p0i8.i64", fn(i8p, i8p, t_i64, t_i32, i1) -> void);
     ifn!("llvm.memset.p0i8.i16", fn(i8p, t_i8, t_i16, t_i32, i1) -> void);
     ifn!("llvm.memset.p0i8.i32", fn(i8p, t_i8, t_i32, t_i32, i1) -> void);
     ifn!("llvm.memset.p0i8.i64", fn(i8p, t_i8, t_i64, t_i32, i1) -> void);
@@ -726,6 +720,18 @@ fn declare_intrinsic(cx: &CodegenCx<'ll, '_>, key: &str) -> Option<&'ll Value> {
     ifn!("llvm.bitreverse.i64", fn(t_i64) -> t_i64);
     ifn!("llvm.bitreverse.i128", fn(t_i128) -> t_i128);
 
+    ifn!("llvm.fshl.i8", fn(t_i8, t_i8, t_i8) -> t_i8);
+    ifn!("llvm.fshl.i16", fn(t_i16, t_i16, t_i16) -> t_i16);
+    ifn!("llvm.fshl.i32", fn(t_i32, t_i32, t_i32) -> t_i32);
+    ifn!("llvm.fshl.i64", fn(t_i64, t_i64, t_i64) -> t_i64);
+    ifn!("llvm.fshl.i128", fn(t_i128, t_i128, t_i128) -> t_i128);
+
+    ifn!("llvm.fshr.i8", fn(t_i8, t_i8, t_i8) -> t_i8);
+    ifn!("llvm.fshr.i16", fn(t_i16, t_i16, t_i16) -> t_i16);
+    ifn!("llvm.fshr.i32", fn(t_i32, t_i32, t_i32) -> t_i32);
+    ifn!("llvm.fshr.i64", fn(t_i64, t_i64, t_i64) -> t_i64);
+    ifn!("llvm.fshr.i128", fn(t_i128, t_i128, t_i128) -> t_i128);
+
     ifn!("llvm.sadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1});
     ifn!("llvm.sadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1});
     ifn!("llvm.sadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1});
diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
index f5e5287cd42..97a3ae9c9fa 100644
--- a/src/librustc_codegen_llvm/debuginfo/metadata.rs
+++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs
@@ -23,6 +23,7 @@ use value::Value;
 use llvm;
 use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor,
                       DICompositeType, DILexicalBlock, DIFlags};
+use llvm_util;
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc::hir::CodegenFnAttrFlags;
@@ -31,9 +32,10 @@ use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
 use rustc::ich::NodeIdHashingMode;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc::ty::Instance;
-use common::CodegenCx;
+use common::{CodegenCx, C_u64};
 use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
-use rustc::ty::layout::{self, Align, LayoutOf, PrimitiveExt, Size, TyLayout};
+use rustc::ty::layout::{self, Align, HasDataLayout, Integer, IntegerExt, LayoutOf,
+                        PrimitiveExt, Size, TyLayout};
 use rustc::session::config;
 use rustc::util::nodemap::FxHashMap;
 use rustc_fs_util::path2cstr;
@@ -96,6 +98,7 @@ pub struct UniqueTypeId(ast::Name);
 // created so far. The metadata nodes are indexed by UniqueTypeId, and, for
 // faster lookup, also by Ty. The TypeMap is responsible for creating
 // UniqueTypeIds.
+#[derive(Default)]
 pub struct TypeMap<'ll, 'tcx> {
     // The UniqueTypeIds created so far
     unique_id_interner: Interner,
@@ -108,15 +111,6 @@ pub struct TypeMap<'ll, 'tcx> {
 }
 
 impl TypeMap<'ll, 'tcx> {
-    pub fn new() -> Self {
-        TypeMap {
-            unique_id_interner: Interner::new(),
-            type_to_metadata: FxHashMap(),
-            unique_id_to_metadata: FxHashMap(),
-            type_to_unique_id: FxHashMap(),
-        }
-    }
-
     // Adds a Ty to metadata mapping to the TypeMap. The method will fail if
     // the mapping already exists.
     fn register_type_with_metadata(
@@ -213,6 +207,7 @@ enum RecursiveTypeDescription<'ll, 'tcx> {
         unfinished_type: Ty<'tcx>,
         unique_type_id: UniqueTypeId,
         metadata_stub: &'ll DICompositeType,
+        member_holding_stub: &'ll DICompositeType,
         member_description_factory: MemberDescriptionFactory<'ll, 'tcx>,
     },
     FinalMetadata(&'ll DICompositeType)
@@ -223,6 +218,7 @@ fn create_and_register_recursive_type_forward_declaration(
     unfinished_type: Ty<'tcx>,
     unique_type_id: UniqueTypeId,
     metadata_stub: &'ll DICompositeType,
+    member_holding_stub: &'ll DICompositeType,
     member_description_factory: MemberDescriptionFactory<'ll, 'tcx>,
 ) -> RecursiveTypeDescription<'ll, 'tcx> {
 
@@ -235,6 +231,7 @@ fn create_and_register_recursive_type_forward_declaration(
         unfinished_type,
         unique_type_id,
         metadata_stub,
+        member_holding_stub,
         member_description_factory,
     }
 }
@@ -250,6 +247,7 @@ impl RecursiveTypeDescription<'ll, 'tcx> {
                 unfinished_type,
                 unique_type_id,
                 metadata_stub,
+                member_holding_stub,
                 ref member_description_factory,
             } => {
                 // Make sure that we have a forward declaration of the type in
@@ -274,7 +272,7 @@ impl RecursiveTypeDescription<'ll, 'tcx> {
 
                 // ... and attach them to the stub to complete it.
                 set_members_of_composite_type(cx,
-                                              metadata_stub,
+                                              member_holding_stub,
                                               member_descriptions);
                 return MetadataCreationResult::new(metadata_stub, true);
             }
@@ -358,6 +356,7 @@ fn vec_slice_metadata(
             size: pointer_size,
             align: pointer_align,
             flags: DIFlags::FlagZero,
+            discriminant: None,
         },
         MemberDescription {
             name: "length".to_owned(),
@@ -366,6 +365,7 @@ fn vec_slice_metadata(
             size: usize_size,
             align: usize_align,
             flags: DIFlags::FlagZero,
+            discriminant: None,
         },
     ];
 
@@ -466,6 +466,7 @@ fn trait_pointer_metadata(
             size: data_ptr_field.size,
             align: data_ptr_field.align,
             flags: DIFlags::FlagArtificial,
+            discriminant: None,
         },
         MemberDescription {
             name: "vtable".to_owned(),
@@ -474,6 +475,7 @@ fn trait_pointer_metadata(
             size: vtable_field.size,
             align: vtable_field.align,
             flags: DIFlags::FlagArtificial,
+            discriminant: None,
         },
     ];
 
@@ -922,6 +924,7 @@ struct MemberDescription<'ll> {
     size: Size,
     align: Align,
     flags: DIFlags,
+    discriminant: Option<u64>,
 }
 
 // A factory for MemberDescriptions. It produces a list of member descriptions
@@ -989,6 +992,7 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> {
                 size,
                 align,
                 flags: DIFlags::FlagZero,
+                discriminant: None,
             }
         }).collect()
     }
@@ -1021,6 +1025,7 @@ fn prepare_struct_metadata(
         struct_type,
         unique_type_id,
         struct_metadata_stub,
+        struct_metadata_stub,
         StructMDF(StructMemberDescriptionFactory {
             ty: struct_type,
             variant,
@@ -1053,6 +1058,7 @@ impl<'tcx> TupleMemberDescriptionFactory<'tcx> {
                 size,
                 align,
                 flags: DIFlags::FlagZero,
+                discriminant: None,
             }
         }).collect()
     }
@@ -1067,15 +1073,18 @@ fn prepare_tuple_metadata(
 ) -> RecursiveTypeDescription<'ll, 'tcx> {
     let tuple_name = compute_debuginfo_type_name(cx, tuple_type, false);
 
+    let struct_stub = create_struct_stub(cx,
+                                         tuple_type,
+                                         &tuple_name[..],
+                                         unique_type_id,
+                                         NO_SCOPE_METADATA);
+
     create_and_register_recursive_type_forward_declaration(
         cx,
         tuple_type,
         unique_type_id,
-        create_struct_stub(cx,
-                           tuple_type,
-                           &tuple_name[..],
-                           unique_type_id,
-                           NO_SCOPE_METADATA),
+        struct_stub,
+        struct_stub,
         TupleMDF(TupleMemberDescriptionFactory {
             ty: tuple_type,
             component_types: component_types.to_vec(),
@@ -1107,6 +1116,7 @@ impl<'tcx> UnionMemberDescriptionFactory<'tcx> {
                 size,
                 align,
                 flags: DIFlags::FlagZero,
+                discriminant: None,
             }
         }).collect()
     }
@@ -1138,6 +1148,7 @@ fn prepare_union_metadata(
         union_type,
         unique_type_id,
         union_metadata_stub,
+        union_metadata_stub,
         UnionMDF(UnionMemberDescriptionFactory {
             layout: cx.layout_of(union_type),
             variant,
@@ -1150,6 +1161,19 @@ fn prepare_union_metadata(
 // Enums
 //=-----------------------------------------------------------------------------
 
+// DWARF variant support is only available starting in LLVM 7.
+// Although the earlier enum debug info output did not work properly
+// in all situations, it is better for the time being to continue to
+// sometimes emit the old style rather than emit something completely
+// useless when rust is compiled against LLVM 6 or older.  This
+// function decides which representation will be emitted.
+fn use_enum_fallback(cx: &CodegenCx) -> bool {
+    // On MSVC we have to use the fallback mode, because LLVM doesn't
+    // lower variant parts to PDB.
+    return cx.sess().target.target.options.is_like_msvc
+        || llvm_util::get_major_version() < 7;
+}
+
 // Describes the members of an enum value: An enum is described as a union of
 // structs in DWARF. This MemberDescriptionFactory provides the description for
 // the members of this union; so for every variant of the given enum, this
@@ -1167,6 +1191,15 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
     fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>)
                                   -> Vec<MemberDescription<'ll>> {
         let adt = &self.enum_type.ty_adt_def().unwrap();
+
+        // This will always find the metadata in the type map.
+        let fallback = use_enum_fallback(cx);
+        let self_metadata = if fallback {
+            self.containing_scope
+        } else {
+            type_metadata(cx, self.enum_type, self.span)
+        };
+
         match self.layout.variants {
             layout::Variants::Single { .. } if adt.variants.is_empty() => vec![],
             layout::Variants::Single { index } => {
@@ -1175,7 +1208,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
                                           self.layout,
                                           &adt.variants[index],
                                           NoDiscriminant,
-                                          self.containing_scope,
+                                          self_metadata,
                                           self.span);
 
                 let member_descriptions =
@@ -1186,26 +1219,36 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
                                               member_descriptions);
                 vec![
                     MemberDescription {
-                        name: String::new(),
+                        name: if fallback {
+                            String::new()
+                        } else {
+                            adt.variants[index].name.as_str().to_string()
+                        },
                         type_metadata: variant_type_metadata,
                         offset: Size::ZERO,
                         size: self.layout.size,
                         align: self.layout.align,
-                        flags: DIFlags::FlagZero
+                        flags: DIFlags::FlagZero,
+                        discriminant: None,
                     }
                 ]
             }
             layout::Variants::Tagged { ref variants, .. } => {
-                let discriminant_info = RegularDiscriminant(self.discriminant_type_metadata
-                    .expect(""));
-                (0..variants.len()).map(|i| {
+                let discriminant_info = if fallback {
+                    RegularDiscriminant(self.discriminant_type_metadata
+                                        .expect(""))
+                } else {
+                    // This doesn't matter in this case.
+                    NoDiscriminant
+                };
+                variants.iter_enumerated().map(|(i, _)| {
                     let variant = self.layout.for_variant(cx, i);
                     let (variant_type_metadata, member_desc_factory) =
                         describe_enum_variant(cx,
                                               variant,
                                               &adt.variants[i],
                                               discriminant_info,
-                                              self.containing_scope,
+                                              self_metadata,
                                               self.span);
 
                     let member_descriptions = member_desc_factory
@@ -1215,75 +1258,127 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
                                                   variant_type_metadata,
                                                   member_descriptions);
                     MemberDescription {
-                        name: String::new(),
+                        name: if fallback {
+                            String::new()
+                        } else {
+                            adt.variants[i].name.as_str().to_string()
+                        },
                         type_metadata: variant_type_metadata,
                         offset: Size::ZERO,
-                        size: variant.size,
-                        align: variant.align,
-                        flags: DIFlags::FlagZero
+                        size: self.layout.size,
+                        align: self.layout.align,
+                        flags: DIFlags::FlagZero,
+                        discriminant: Some(self.layout.ty.ty_adt_def().unwrap()
+                                           .discriminant_for_variant(cx.tcx, i)
+                                           .val as u64),
                     }
                 }).collect()
             }
-            layout::Variants::NicheFilling { dataful_variant, ref niche_variants, .. } => {
-                let variant = self.layout.for_variant(cx, dataful_variant);
-                // Create a description of the non-null variant
-                let (variant_type_metadata, member_description_factory) =
-                    describe_enum_variant(cx,
-                                          variant,
-                                          &adt.variants[dataful_variant],
-                                          OptimizedDiscriminant,
-                                          self.containing_scope,
-                                          self.span);
+            layout::Variants::NicheFilling {
+                ref niche_variants,
+                niche_start,
+                ref variants,
+                dataful_variant,
+                ref niche,
+            } => {
+                if fallback {
+                    let variant = self.layout.for_variant(cx, dataful_variant);
+                    // Create a description of the non-null variant
+                    let (variant_type_metadata, member_description_factory) =
+                        describe_enum_variant(cx,
+                                              variant,
+                                              &adt.variants[dataful_variant],
+                                              OptimizedDiscriminant,
+                                              self.containing_scope,
+                                              self.span);
 
-                let variant_member_descriptions =
-                    member_description_factory.create_member_descriptions(cx);
+                    let variant_member_descriptions =
+                        member_description_factory.create_member_descriptions(cx);
 
-                set_members_of_composite_type(cx,
-                                              variant_type_metadata,
-                                              variant_member_descriptions);
-
-                // Encode the information about the null variant in the union
-                // member's name.
-                let mut name = String::from("RUST$ENCODED$ENUM$");
-                // HACK(eddyb) the debuggers should just handle offset+size
-                // of discriminant instead of us having to recover its path.
-                // Right now it's not even going to work for `niche_start > 0`,
-                // and for multiple niche variants it only supports the first.
-                fn compute_field_path<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
-                                                name: &mut String,
-                                                layout: TyLayout<'tcx>,
-                                                offset: Size,
-                                                size: Size) {
-                    for i in 0..layout.fields.count() {
-                        let field_offset = layout.fields.offset(i);
-                        if field_offset > offset {
-                            continue;
-                        }
-                        let inner_offset = offset - field_offset;
-                        let field = layout.field(cx, i);
-                        if inner_offset + size <= field.size {
-                            write!(name, "{}$", i).unwrap();
-                            compute_field_path(cx, name, field, inner_offset, size);
+                    set_members_of_composite_type(cx,
+                                                  variant_type_metadata,
+                                                  variant_member_descriptions);
+
+                    // Encode the information about the null variant in the union
+                    // member's name.
+                    let mut name = String::from("RUST$ENCODED$ENUM$");
+                    // Right now it's not even going to work for `niche_start > 0`,
+                    // and for multiple niche variants it only supports the first.
+                    fn compute_field_path<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
+                                                    name: &mut String,
+                                                    layout: TyLayout<'tcx>,
+                                                    offset: Size,
+                                                    size: Size) {
+                        for i in 0..layout.fields.count() {
+                            let field_offset = layout.fields.offset(i);
+                            if field_offset > offset {
+                                continue;
+                            }
+                            let inner_offset = offset - field_offset;
+                            let field = layout.field(cx, i);
+                            if inner_offset + size <= field.size {
+                                write!(name, "{}$", i).unwrap();
+                                compute_field_path(cx, name, field, inner_offset, size);
+                            }
                         }
                     }
+                    compute_field_path(cx, &mut name,
+                                       self.layout,
+                                       self.layout.fields.offset(0),
+                                       self.layout.field(cx, 0).size);
+                    name.push_str(&adt.variants[*niche_variants.start()].name.as_str());
+
+                    // Create the (singleton) list of descriptions of union members.
+                    vec![
+                        MemberDescription {
+                            name,
+                            type_metadata: variant_type_metadata,
+                            offset: Size::ZERO,
+                            size: variant.size,
+                            align: variant.align,
+                            flags: DIFlags::FlagZero,
+                            discriminant: None,
+                        }
+                    ]
+                } else {
+                    variants.iter_enumerated().map(|(i, _)| {
+                        let variant = self.layout.for_variant(cx, i);
+                        let (variant_type_metadata, member_desc_factory) =
+                            describe_enum_variant(cx,
+                                                  variant,
+                                                  &adt.variants[i],
+                                                  OptimizedDiscriminant,
+                                                  self_metadata,
+                                                  self.span);
+
+                        let member_descriptions = member_desc_factory
+                            .create_member_descriptions(cx);
+
+                        set_members_of_composite_type(cx,
+                                                      variant_type_metadata,
+                                                      member_descriptions);
+
+                        let niche_value = if i == dataful_variant {
+                            None
+                        } else {
+                            let value = (i.as_u32() as u128)
+                                .wrapping_sub(niche_variants.start().as_u32() as u128)
+                                .wrapping_add(niche_start);
+                            let value = value & ((1u128 << niche.value.size(cx).bits()) - 1);
+                            Some(value as u64)
+                        };
+
+                        MemberDescription {
+                            name: adt.variants[i].name.as_str().to_string(),
+                            type_metadata: variant_type_metadata,
+                            offset: Size::ZERO,
+                            size: self.layout.size,
+                            align: self.layout.align,
+                            flags: DIFlags::FlagZero,
+                            discriminant: niche_value,
+                        }
+                    }).collect()
                 }
-                compute_field_path(cx, &mut name,
-                                   self.layout,
-                                   self.layout.fields.offset(0),
-                                   self.layout.field(cx, 0).size);
-                name.push_str(&adt.variants[*niche_variants.start()].name.as_str());
-
-                // Create the (singleton) list of descriptions of union members.
-                vec![
-                    MemberDescription {
-                        name,
-                        type_metadata: variant_type_metadata,
-                        offset: Size::ZERO,
-                        size: variant.size,
-                        align: variant.align,
-                        flags: DIFlags::FlagZero
-                    }
-                ]
             }
         }
     }
@@ -1305,14 +1400,19 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> {
             let (size, align) = cx.size_and_align_of(ty);
             MemberDescription {
                 name: name.to_string(),
-                type_metadata: match self.discriminant_type_metadata {
-                    Some(metadata) if i == 0 => metadata,
-                    _ => type_metadata(cx, ty, self.span)
+                type_metadata: if use_enum_fallback(cx) {
+                    match self.discriminant_type_metadata {
+                        Some(metadata) if i == 0 => metadata,
+                        _ => type_metadata(cx, ty, self.span)
+                    }
+                } else {
+                    type_metadata(cx, ty, self.span)
                 },
                 offset: self.offsets[i],
                 size,
                 align,
-                flags: DIFlags::FlagZero
+                flags: DIFlags::FlagZero,
+                discriminant: None,
             }
         }).collect()
     }
@@ -1325,10 +1425,10 @@ enum EnumDiscriminantInfo<'ll> {
     NoDiscriminant
 }
 
-// Returns a tuple of (1) type_metadata_stub of the variant, (2) the llvm_type
-// of the variant, and (3) a MemberDescriptionFactory for producing the
-// descriptions of the fields of the variant. This is a rudimentary version of a
-// full RecursiveTypeDescription.
+// Returns a tuple of (1) type_metadata_stub of the variant, (2) a
+// MemberDescriptionFactory for producing the descriptions of the
+// fields of the variant. This is a rudimentary version of a full
+// RecursiveTypeDescription.
 fn describe_enum_variant(
     cx: &CodegenCx<'ll, 'tcx>,
     layout: layout::TyLayout<'tcx>,
@@ -1351,29 +1451,46 @@ fn describe_enum_variant(
                                            unique_type_id,
                                            Some(containing_scope));
 
-    // If this is not a univariant enum, there is also the discriminant field.
-    let (discr_offset, discr_arg) = match discriminant_info {
-        RegularDiscriminant(_) => {
-            // We have the layout of an enum variant, we need the layout of the outer enum
-            let enum_layout = cx.layout_of(layout.ty);
-            (Some(enum_layout.fields.offset(0)),
-             Some(("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, 0).ty)))
-        }
-        _ => (None, None),
-    };
-    let offsets = discr_offset.into_iter().chain((0..layout.fields.count()).map(|i| {
-        layout.fields.offset(i)
-    })).collect();
-
     // Build an array of (field name, field type) pairs to be captured in the factory closure.
-    let args = discr_arg.into_iter().chain((0..layout.fields.count()).map(|i| {
-        let name = if variant.ctor_kind == CtorKind::Fn {
-            format!("__{}", i)
-        } else {
-            variant.fields[i].ident.to_string()
+    let (offsets, args) = if use_enum_fallback(cx) {
+        // If this is not a univariant enum, there is also the discriminant field.
+        let (discr_offset, discr_arg) = match discriminant_info {
+            RegularDiscriminant(_) => {
+                // We have the layout of an enum variant, we need the layout of the outer enum
+                let enum_layout = cx.layout_of(layout.ty);
+                (Some(enum_layout.fields.offset(0)),
+                 Some(("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, 0).ty)))
+            }
+            _ => (None, None),
         };
-        (name, layout.field(cx, i).ty)
-    })).collect();
+        (
+            discr_offset.into_iter().chain((0..layout.fields.count()).map(|i| {
+                layout.fields.offset(i)
+            })).collect(),
+            discr_arg.into_iter().chain((0..layout.fields.count()).map(|i| {
+                let name = if variant.ctor_kind == CtorKind::Fn {
+                    format!("__{}", i)
+                } else {
+                    variant.fields[i].ident.to_string()
+                };
+                (name, layout.field(cx, i).ty)
+            })).collect()
+        )
+    } else {
+        (
+            (0..layout.fields.count()).map(|i| {
+                layout.fields.offset(i)
+            }).collect(),
+            (0..layout.fields.count()).map(|i| {
+                let name = if variant.ctor_kind == CtorKind::Fn {
+                    format!("__{}", i)
+                } else {
+                    variant.fields[i].ident.to_string()
+                };
+                (name, layout.field(cx, i).ty)
+            }).collect()
+        )
+    };
 
     let member_description_factory =
         VariantMDF(VariantMemberDescriptionFactory {
@@ -1409,22 +1526,22 @@ fn prepare_enum_metadata(
     // <unknown>
     let file_metadata = unknown_file_metadata(cx);
 
-    let def = enum_type.ty_adt_def().unwrap();
-    let enumerators_metadata: Vec<_> = def.discriminants(cx.tcx)
-        .zip(&def.variants)
-        .map(|(discr, v)| {
-            let name = SmallCStr::new(&v.name.as_str());
-            unsafe {
-                Some(llvm::LLVMRustDIBuilderCreateEnumerator(
-                    DIB(cx),
-                    name.as_ptr(),
-                    // FIXME: what if enumeration has i128 discriminant?
-                    discr.val as u64))
-            }
-        })
-        .collect();
-
     let discriminant_type_metadata = |discr: layout::Primitive| {
+        let def = enum_type.ty_adt_def().unwrap();
+        let enumerators_metadata: Vec<_> = def.discriminants(cx.tcx)
+            .zip(&def.variants)
+            .map(|((_, discr), v)| {
+                let name = SmallCStr::new(&v.name.as_str());
+                unsafe {
+                    Some(llvm::LLVMRustDIBuilderCreateEnumerator(
+                        DIB(cx),
+                        name.as_ptr(),
+                        // FIXME: what if enumeration has i128 discriminant?
+                        discr.val as u64))
+                }
+            })
+            .collect();
+
         let disr_type_key = (enum_def_id, discr);
         let cached_discriminant_type_metadata = debug_context(cx).created_enum_disr_types
                                                                  .borrow()
@@ -1449,7 +1566,7 @@ fn prepare_enum_metadata(
                         discriminant_size.bits(),
                         discriminant_align.abi_bits() as u32,
                         create_DIArray(DIB(cx), &enumerators_metadata),
-                        discriminant_base_type_metadata)
+                        discriminant_base_type_metadata, true)
                 };
 
                 debug_context(cx).created_enum_disr_types
@@ -1463,16 +1580,10 @@ fn prepare_enum_metadata(
 
     let layout = cx.layout_of(enum_type);
 
-    let discriminant_type_metadata = match layout.variants {
-        layout::Variants::Single { .. } |
-        layout::Variants::NicheFilling { .. } => None,
-        layout::Variants::Tagged { ref tag, .. } => {
-            Some(discriminant_type_metadata(tag.value))
-        }
-    };
-
-    if let (&layout::Abi::Scalar(_), Some(discr)) = (&layout.abi, discriminant_type_metadata) {
-        return FinalMetadata(discr);
+    match (&layout.abi, &layout.variants) {
+        (&layout::Abi::Scalar(_), &layout::Variants::Tagged {ref tag, .. }) =>
+            return FinalMetadata(discriminant_type_metadata(tag.value)),
+        _ => {}
     }
 
     let (enum_type_size, enum_type_align) = layout.size_and_align();
@@ -1481,30 +1592,145 @@ fn prepare_enum_metadata(
     let unique_type_id_str = SmallCStr::new(
         debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id)
     );
-    let enum_metadata = unsafe {
-        llvm::LLVMRustDIBuilderCreateUnionType(
-        DIB(cx),
-        containing_scope,
-        enum_name.as_ptr(),
-        file_metadata,
-        UNKNOWN_LINE_NUMBER,
-        enum_type_size.bits(),
-        enum_type_align.abi_bits() as u32,
-        DIFlags::FlagZero,
-        None,
-        0, // RuntimeLang
-        unique_type_id_str.as_ptr())
+
+    if use_enum_fallback(cx) {
+        let discriminant_type_metadata = match layout.variants {
+            layout::Variants::Single { .. } |
+            layout::Variants::NicheFilling { .. } => None,
+            layout::Variants::Tagged { ref tag, .. } => {
+                Some(discriminant_type_metadata(tag.value))
+            }
+        };
+
+        let enum_metadata = unsafe {
+            llvm::LLVMRustDIBuilderCreateUnionType(
+                DIB(cx),
+                containing_scope,
+                enum_name.as_ptr(),
+                file_metadata,
+                UNKNOWN_LINE_NUMBER,
+                enum_type_size.bits(),
+                enum_type_align.abi_bits() as u32,
+                DIFlags::FlagZero,
+                None,
+                0, // RuntimeLang
+                unique_type_id_str.as_ptr())
+        };
+
+        return create_and_register_recursive_type_forward_declaration(
+            cx,
+            enum_type,
+            unique_type_id,
+            enum_metadata,
+            enum_metadata,
+            EnumMDF(EnumMemberDescriptionFactory {
+                enum_type,
+                layout,
+                discriminant_type_metadata,
+                containing_scope,
+                span,
+            }),
+        );
+    }
+
+    let discriminator_metadata = match &layout.variants {
+        // A single-variant enum has no discriminant.
+        &layout::Variants::Single { .. } => None,
+
+        &layout::Variants::NicheFilling { ref niche, .. } => {
+            // Find the integer type of the correct size.
+            let size = niche.value.size(cx);
+            let align = niche.value.align(cx);
+
+            let discr_type = match niche.value {
+                layout::Int(t, _) => t,
+                layout::Float(layout::FloatTy::F32) => Integer::I32,
+                layout::Float(layout::FloatTy::F64) => Integer::I64,
+                layout::Pointer => cx.data_layout().ptr_sized_integer(),
+            }.to_ty(cx.tcx, false);
+
+            let discr_metadata = basic_type_metadata(cx, discr_type);
+            unsafe {
+                Some(llvm::LLVMRustDIBuilderCreateMemberType(
+                    DIB(cx),
+                    containing_scope,
+                    ptr::null_mut(),
+                    file_metadata,
+                    UNKNOWN_LINE_NUMBER,
+                    size.bits(),
+                    align.abi_bits() as u32,
+                    layout.fields.offset(0).bits(),
+                    DIFlags::FlagArtificial,
+                    discr_metadata))
+            }
+        },
+
+        &layout::Variants::Tagged { ref tag, .. } => {
+            let discr_type = tag.value.to_ty(cx.tcx);
+            let (size, align) = cx.size_and_align_of(discr_type);
+
+            let discr_metadata = basic_type_metadata(cx, discr_type);
+            unsafe {
+                Some(llvm::LLVMRustDIBuilderCreateMemberType(
+                    DIB(cx),
+                    containing_scope,
+                    ptr::null_mut(),
+                    file_metadata,
+                    UNKNOWN_LINE_NUMBER,
+                    size.bits(),
+                    align.abi_bits() as u32,
+                    layout.fields.offset(0).bits(),
+                    DIFlags::FlagArtificial,
+                    discr_metadata))
+            }
+        },
+    };
+
+    let empty_array = create_DIArray(DIB(cx), &[]);
+    let variant_part = unsafe {
+        llvm::LLVMRustDIBuilderCreateVariantPart(
+            DIB(cx),
+            containing_scope,
+            ptr::null_mut(),
+            file_metadata,
+            UNKNOWN_LINE_NUMBER,
+            enum_type_size.bits(),
+            enum_type_align.abi_bits() as u32,
+            DIFlags::FlagZero,
+            discriminator_metadata,
+            empty_array,
+            unique_type_id_str.as_ptr())
+    };
+
+    // The variant part must be wrapped in a struct according to DWARF.
+    let type_array = create_DIArray(DIB(cx), &[Some(variant_part)]);
+    let struct_wrapper = unsafe {
+        llvm::LLVMRustDIBuilderCreateStructType(
+            DIB(cx),
+            Some(containing_scope),
+            enum_name.as_ptr(),
+            file_metadata,
+            UNKNOWN_LINE_NUMBER,
+            enum_type_size.bits(),
+            enum_type_align.abi_bits() as u32,
+            DIFlags::FlagZero,
+            None,
+            type_array,
+            0,
+            None,
+            unique_type_id_str.as_ptr())
     };
 
     return create_and_register_recursive_type_forward_declaration(
         cx,
         enum_type,
         unique_type_id,
-        enum_metadata,
+        struct_wrapper,
+        variant_part,
         EnumMDF(EnumMemberDescriptionFactory {
             enum_type,
             layout,
-            discriminant_type_metadata,
+            discriminant_type_metadata: None,
             containing_scope,
             span,
         }),
@@ -1573,7 +1799,7 @@ fn set_members_of_composite_type(cx: &CodegenCx<'ll, '_>,
         .map(|member_description| {
             let member_name = CString::new(member_description.name).unwrap();
             unsafe {
-                Some(llvm::LLVMRustDIBuilderCreateMemberType(
+                Some(llvm::LLVMRustDIBuilderCreateVariantMemberType(
                     DIB(cx),
                     composite_type_metadata,
                     member_name.as_ptr(),
@@ -1582,6 +1808,10 @@ fn set_members_of_composite_type(cx: &CodegenCx<'ll, '_>,
                     member_description.size.bits(),
                     member_description.align.abi_bits() as u32,
                     member_description.offset.bits(),
+                    match member_description.discriminant {
+                        None => None,
+                        Some(value) => Some(C_u64(cx, value)),
+                    },
                     member_description.flags,
                     member_description.type_metadata))
             }
diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs
index acb79d6f568..042e72e921e 100644
--- a/src/librustc_codegen_llvm/debuginfo/mod.rs
+++ b/src/librustc_codegen_llvm/debuginfo/mod.rs
@@ -100,11 +100,11 @@ impl<'a, 'tcx> CrateDebugContext<'a, 'tcx> {
             llcontext,
             llmod,
             builder,
-            created_files: RefCell::new(FxHashMap()),
-            created_enum_disr_types: RefCell::new(FxHashMap()),
-            type_map: RefCell::new(TypeMap::new()),
+            created_files: Default::default(),
+            created_enum_disr_types: Default::default(),
+            type_map: Default::default(),
             namespace_map: RefCell::new(DefIdMap()),
-            composite_types_completed: RefCell::new(FxHashSet()),
+            composite_types_completed: Default::default(),
         }
     }
 }
diff --git a/src/librustc_codegen_llvm/debuginfo/type_names.rs b/src/librustc_codegen_llvm/debuginfo/type_names.rs
index f5abb527e43..eb5ae81b218 100644
--- a/src/librustc_codegen_llvm/debuginfo/type_names.rs
+++ b/src/librustc_codegen_llvm/debuginfo/type_names.rs
@@ -173,6 +173,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
         ty::Infer(_) |
         ty::UnnormalizedProjection(..) |
         ty::Projection(..) |
+        ty::Bound(..) |
         ty::Opaque(..) |
         ty::GeneratorWitness(..) |
         ty::Param(_) => {
diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs
index 26969e24f08..f4aede55ce1 100644
--- a/src/librustc_codegen_llvm/declare.rs
+++ b/src/librustc_codegen_llvm/declare.rs
@@ -22,7 +22,7 @@
 
 use llvm;
 use llvm::AttributePlace::Function;
-use rustc::ty::{self, Ty};
+use rustc::ty::{self, PolyFnSig};
 use rustc::ty::layout::LayoutOf;
 use rustc::session::config::Sanitizer;
 use rustc_data_structures::small_c_str::SmallCStr;
@@ -30,7 +30,6 @@ use rustc_target::spec::PanicStrategy;
 use abi::{Abi, FnType, FnTypeExt};
 use attributes;
 use context::CodegenCx;
-use common;
 use type_::Type;
 use value::Value;
 
@@ -129,10 +128,9 @@ pub fn declare_cfn(cx: &CodegenCx<'ll, '_>, name: &str, fn_type: &'ll Type) -> &
 pub fn declare_fn(
     cx: &CodegenCx<'ll, 'tcx>,
     name: &str,
-    fn_type: Ty<'tcx>,
+    sig: PolyFnSig<'tcx>,
 ) -> &'ll Value {
-    debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type);
-    let sig = common::ty_fn_sig(cx, fn_type);
+    debug!("declare_rust_fn(name={:?}, sig={:?})", name, sig);
     let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
     debug!("declare_rust_fn (after region erasure) sig={:?}", sig);
 
@@ -184,12 +182,12 @@ pub fn define_private_global(cx: &CodegenCx<'ll, '_>, ty: &'ll Type) -> &'ll Val
 pub fn define_fn(
     cx: &CodegenCx<'ll, 'tcx>,
     name: &str,
-    fn_type: Ty<'tcx>,
+    fn_sig: PolyFnSig<'tcx>,
 ) -> &'ll Value {
     if get_defined_value(cx, name).is_some() {
         cx.sess().fatal(&format!("symbol `{}` already defined", name))
     } else {
-        declare_fn(cx, name, fn_type)
+        declare_fn(cx, name, fn_sig)
     }
 }
 
@@ -201,9 +199,9 @@ pub fn define_fn(
 pub fn define_internal_fn(
     cx: &CodegenCx<'ll, 'tcx>,
     name: &str,
-    fn_type: Ty<'tcx>,
+    fn_sig: PolyFnSig<'tcx>,
 ) -> &'ll Value {
-    let llfn = define_fn(cx, name, fn_type);
+    let llfn = define_fn(cx, name, fn_sig);
     unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage) };
     llfn
 }
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index 272196afa6f..a5f90149f4a 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -13,6 +13,7 @@
 use attributes;
 use intrinsics::{self, Intrinsic};
 use llvm::{self, TypeKind};
+use llvm_util;
 use abi::{Abi, FnType, LlvmType, PassMode};
 use mir::place::PlaceRef;
 use mir::operand::{OperandRef, OperandValue};
@@ -23,7 +24,7 @@ use glue;
 use type_::Type;
 use type_of::LayoutLlvmExt;
 use rustc::ty::{self, Ty};
-use rustc::ty::layout::{HasDataLayout, LayoutOf};
+use rustc::ty::layout::LayoutOf;
 use rustc::hir;
 use syntax::ast;
 use syntax::symbol::Symbol;
@@ -284,7 +285,8 @@ pub fn codegen_intrinsic_call(
         "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "ctpop" | "bswap" |
         "bitreverse" | "add_with_overflow" | "sub_with_overflow" |
         "mul_with_overflow" | "overflowing_add" | "overflowing_sub" | "overflowing_mul" |
-        "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" | "exact_div" => {
+        "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" | "exact_div" |
+        "rotate_left" | "rotate_right" => {
             let ty = arg_tys[0];
             match int_type_width_signed(ty, cx) {
                 Some((width, signed)) =>
@@ -363,6 +365,27 @@ pub fn codegen_intrinsic_call(
                             } else {
                                 bx.lshr(args[0].immediate(), args[1].immediate())
                             },
+                        "rotate_left" | "rotate_right" => {
+                            let is_left = name == "rotate_left";
+                            let val = args[0].immediate();
+                            let raw_shift = args[1].immediate();
+                            if llvm_util::get_major_version() >= 7 {
+                                // rotate = funnel shift with first two args the same
+                                let llvm_name = &format!("llvm.fsh{}.i{}",
+                                                         if is_left { 'l' } else { 'r' }, width);
+                                let llfn = cx.get_intrinsic(llvm_name);
+                                bx.call(llfn, &[val, val, raw_shift], None)
+                            } else {
+                                // rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW))
+                                // rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW))
+                                let width = C_uint(Type::ix(cx, width), width);
+                                let shift = bx.urem(raw_shift, width);
+                                let inv_shift = bx.urem(bx.sub(width, raw_shift), width);
+                                let shift1 = bx.shl(val, if is_left { shift } else { inv_shift });
+                                let shift2 = bx.lshr(val, if !is_left { shift } else { inv_shift });
+                                bx.or(shift1, shift2)
+                            }
+                        },
                         _ => bug!(),
                     },
                 None => {
@@ -477,8 +500,8 @@ pub fn codegen_intrinsic_call(
                 "load" => {
                     let ty = substs.type_at(0);
                     if int_type_width_signed(ty, cx).is_some() {
-                        let align = cx.align_of(ty);
-                        bx.atomic_load(args[0].immediate(), order, align)
+                        let size = cx.size_of(ty);
+                        bx.atomic_load(args[0].immediate(), order, size)
                     } else {
                         return invalid_monomorphization(ty);
                     }
@@ -487,8 +510,8 @@ pub fn codegen_intrinsic_call(
                 "store" => {
                     let ty = substs.type_at(0);
                     if int_type_width_signed(ty, cx).is_some() {
-                        let align = cx.align_of(ty);
-                        bx.atomic_store(args[1].immediate(), args[0].immediate(), order, align);
+                        let size = cx.size_of(ty);
+                        bx.atomic_store(args[1].immediate(), args[0].immediate(), order, size);
                         return;
                     } else {
                         return invalid_monomorphization(ty);
@@ -690,28 +713,14 @@ fn copy_intrinsic(
     let cx = bx.cx;
     let (size, align) = cx.size_and_align_of(ty);
     let size = C_usize(cx, size.bytes());
-    let align = C_i32(cx, align.abi() as i32);
-
-    let operation = if allow_overlap {
-        "memmove"
-    } else {
-        "memcpy"
-    };
-
-    let name = format!("llvm.{}.p0i8.p0i8.i{}", operation,
-                       cx.data_layout().pointer_size.bits());
-
+    let align = align.abi();
     let dst_ptr = bx.pointercast(dst, Type::i8p(cx));
     let src_ptr = bx.pointercast(src, Type::i8p(cx));
-    let llfn = cx.get_intrinsic(&name);
-
-    bx.call(llfn,
-        &[dst_ptr,
-        src_ptr,
-        bx.mul(size, count),
-        align,
-        C_bool(cx, volatile)],
-        None)
+    if allow_overlap {
+        bx.memmove(dst_ptr, align, src_ptr, align, bx.mul(size, count), volatile)
+    } else {
+        bx.memcpy(dst_ptr, align, src_ptr, align, bx.mul(size, count), volatile)
+    }
 }
 
 fn memset_intrinsic(
@@ -933,14 +942,14 @@ fn gen_fn<'ll, 'tcx>(
     output: Ty<'tcx>,
     codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>),
 ) -> &'ll Value {
-    let rust_fn_ty = cx.tcx.mk_fn_ptr(ty::Binder::bind(cx.tcx.mk_fn_sig(
+    let rust_fn_sig = ty::Binder::bind(cx.tcx.mk_fn_sig(
         inputs.into_iter(),
         output,
         false,
         hir::Unsafety::Unsafe,
         Abi::Rust
-    )));
-    let llfn = declare::define_internal_fn(cx, name, rust_fn_ty);
+    ));
+    let llfn = declare::define_internal_fn(cx, name, rust_fn_sig);
     attributes::from_fn_attrs(cx, llfn, None);
     let bx = Builder::new_block(cx, llfn, "entry-block");
     codegen(bx);
diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs
index 63a8ab077e5..5d9bae5412e 100644
--- a/src/librustc_codegen_llvm/lib.rs
+++ b/src/librustc_codegen_llvm/lib.rs
@@ -71,7 +71,6 @@ use back::bytecode::RLIB_BYTECODE_EXTENSION;
 
 pub use llvm_util::target_features;
 use std::any::Any;
-use std::path::{PathBuf};
 use std::sync::mpsc;
 use rustc_data_structures::sync::Lrc;
 
@@ -87,20 +86,17 @@ use rustc::util::time_graph;
 use rustc::util::nodemap::{FxHashSet, FxHashMap};
 use rustc::util::profiling::ProfileCategory;
 use rustc_mir::monomorphize;
+use rustc_codegen_utils::{CompiledModule, ModuleKind};
 use rustc_codegen_utils::codegen_backend::CodegenBackend;
 use rustc_data_structures::svh::Svh;
 
 mod diagnostics;
 
 mod back {
-    pub use rustc_codegen_utils::symbol_names;
     mod archive;
     pub mod bytecode;
-    mod command;
-    pub mod linker;
     pub mod link;
     pub mod lto;
-    pub mod symbol_export;
     pub mod write;
     mod rpath;
     pub mod wasm;
@@ -194,15 +190,15 @@ impl CodegenBackend for LlvmCodegenBackend {
     }
 
     fn provide(&self, providers: &mut ty::query::Providers) {
-        back::symbol_names::provide(providers);
-        back::symbol_export::provide(providers);
-        base::provide(providers);
+        rustc_codegen_utils::symbol_export::provide(providers);
+        rustc_codegen_utils::symbol_names::provide(providers);
+        base::provide_both(providers);
         attributes::provide(providers);
     }
 
     fn provide_extern(&self, providers: &mut ty::query::Providers) {
-        back::symbol_export::provide_extern(providers);
-        base::provide_extern(providers);
+        rustc_codegen_utils::symbol_export::provide_extern(providers);
+        base::provide_both(providers);
         attributes::provide_extern(providers);
     }
 
@@ -281,13 +277,6 @@ struct CachedModuleCodegen {
     source: WorkProduct,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq)]
-enum ModuleKind {
-    Regular,
-    Metadata,
-    Allocator,
-}
-
 impl ModuleCodegen {
     fn into_compiled_module(self,
                             emit_obj: bool,
@@ -321,15 +310,6 @@ impl ModuleCodegen {
     }
 }
 
-#[derive(Debug)]
-struct CompiledModule {
-    name: String,
-    kind: ModuleKind,
-    object: Option<PathBuf>,
-    bytecode: Option<PathBuf>,
-    bytecode_compressed: Option<PathBuf>,
-}
-
 struct ModuleLlvm {
     llcx: &'static mut llvm::Context,
     llmod_raw: *const llvm::Module,
@@ -377,7 +357,7 @@ struct CodegenResults {
     crate_hash: Svh,
     metadata: rustc::middle::cstore::EncodedMetadata,
     windows_subsystem: Option<String>,
-    linker_info: back::linker::LinkerInfo,
+    linker_info: rustc_codegen_utils::linker::LinkerInfo,
     crate_info: CrateInfo,
 }
 
diff --git a/src/librustc_codegen_llvm/llvm/archive_ro.rs b/src/librustc_codegen_llvm/llvm/archive_ro.rs
index e0a9f31e508..2a77f256e3a 100644
--- a/src/librustc_codegen_llvm/llvm/archive_ro.rs
+++ b/src/librustc_codegen_llvm/llvm/archive_ro.rs
@@ -40,7 +40,7 @@ impl ArchiveRO {
         return unsafe {
             let s = path2cstr(dst);
             let ar = super::LLVMRustOpenArchive(s.as_ptr()).ok_or_else(|| {
-                super::last_error().unwrap_or("failed to open archive".to_owned())
+                super::last_error().unwrap_or_else(|| "failed to open archive".to_owned())
             })?;
             Ok(ArchiveRO { raw: ar })
         };
diff --git a/src/librustc_codegen_llvm/llvm/diagnostic.rs b/src/librustc_codegen_llvm/llvm/diagnostic.rs
index c41a5f74ae3..b080c51c83a 100644
--- a/src/librustc_codegen_llvm/llvm/diagnostic.rs
+++ b/src/librustc_codegen_llvm/llvm/diagnostic.rs
@@ -77,7 +77,7 @@ impl OptimizationDiagnostic<'ll> {
             ).ok()
         ).ok();
 
-        let mut filename = filename.unwrap_or(String::new());
+        let mut filename = filename.unwrap_or_default();
         if filename.is_empty() {
             filename.push_str("<unknown file>");
         }
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index 0b98fa4eaf5..612581c1ac6 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -998,6 +998,22 @@ extern "C" {
                              Bundle: Option<&OperandBundleDef<'a>>,
                              Name: *const c_char)
                              -> &'a Value;
+    pub fn LLVMRustBuildMemCpy(B: &Builder<'a>,
+                               Dst: &'a Value,
+                               DstAlign: c_uint,
+                               Src: &'a Value,
+                               SrcAlign: c_uint,
+                               Size: &'a Value,
+                               IsVolatile: bool)
+                               -> &'a Value;
+    pub fn LLVMRustBuildMemMove(B: &Builder<'a>,
+                                Dst: &'a Value,
+                                DstAlign: c_uint,
+                                Src: &'a Value,
+                                SrcAlign: c_uint,
+                                Size: &'a Value,
+                                IsVolatile: bool)
+                                -> &'a Value;
     pub fn LLVMBuildSelect(B: &Builder<'a>,
                            If: &'a Value,
                            Then: &'a Value,
@@ -1041,42 +1057,42 @@ extern "C" {
     pub fn LLVMRustBuildVectorReduceFAdd(B: &Builder<'a>,
                                          Acc: &'a Value,
                                          Src: &'a Value)
-                                         -> Option<&'a Value>;
+                                         -> &'a Value;
     pub fn LLVMRustBuildVectorReduceFMul(B: &Builder<'a>,
                                          Acc: &'a Value,
                                          Src: &'a Value)
-                                         -> Option<&'a Value>;
+                                         -> &'a Value;
     pub fn LLVMRustBuildVectorReduceAdd(B: &Builder<'a>,
                                         Src: &'a Value)
-                                        -> Option<&'a Value>;
+                                        -> &'a Value;
     pub fn LLVMRustBuildVectorReduceMul(B: &Builder<'a>,
                                         Src: &'a Value)
-                                        -> Option<&'a Value>;
+                                        -> &'a Value;
     pub fn LLVMRustBuildVectorReduceAnd(B: &Builder<'a>,
                                         Src: &'a Value)
-                                        -> Option<&'a Value>;
+                                        -> &'a Value;
     pub fn LLVMRustBuildVectorReduceOr(B: &Builder<'a>,
                                        Src: &'a Value)
-                                       -> Option<&'a Value>;
+                                       -> &'a Value;
     pub fn LLVMRustBuildVectorReduceXor(B: &Builder<'a>,
                                         Src: &'a Value)
-                                        -> Option<&'a Value>;
+                                        -> &'a Value;
     pub fn LLVMRustBuildVectorReduceMin(B: &Builder<'a>,
                                         Src: &'a Value,
                                         IsSigned: bool)
-                                        -> Option<&'a Value>;
+                                        -> &'a Value;
     pub fn LLVMRustBuildVectorReduceMax(B: &Builder<'a>,
                                         Src: &'a Value,
                                         IsSigned: bool)
-                                        -> Option<&'a Value>;
+                                        -> &'a Value;
     pub fn LLVMRustBuildVectorReduceFMin(B: &Builder<'a>,
                                          Src: &'a Value,
                                          IsNaN: bool)
-                                         -> Option<&'a Value>;
+                                         -> &'a Value;
     pub fn LLVMRustBuildVectorReduceFMax(B: &Builder<'a>,
                                          Src: &'a Value,
                                          IsNaN: bool)
-                                         -> Option<&'a Value>;
+                                         -> &'a Value;
 
     pub fn LLVMRustBuildMinNum(
         B: &Builder<'a>,
@@ -1157,7 +1173,7 @@ extern "C" {
                                                         RunInliner: Bool);
     pub fn LLVMRustPassManagerBuilderPopulateThinLTOPassManager(
         PMB: &PassManagerBuilder,
-        PM: &PassManager) -> bool;
+        PM: &PassManager);
 
     // Stuff that's in rustllvm/ because it's not upstream yet.
 
@@ -1307,6 +1323,19 @@ extern "C" {
                                              Ty: &'a DIType)
                                              -> &'a DIDerivedType;
 
+    pub fn LLVMRustDIBuilderCreateVariantMemberType(Builder: &DIBuilder<'a>,
+                                                    Scope: &'a DIScope,
+                                                    Name: *const c_char,
+                                                    File: &'a DIFile,
+                                                    LineNumber: c_uint,
+                                                    SizeInBits: u64,
+                                                    AlignInBits: u32,
+                                                    OffsetInBits: u64,
+                                                    Discriminant: Option<&'a Value>,
+                                                    Flags: DIFlags,
+                                                    Ty: &'a DIType)
+                                                    -> &'a DIType;
+
     pub fn LLVMRustDIBuilderCreateLexicalBlock(Builder: &DIBuilder<'a>,
                                                Scope: &'a DIScope,
                                                File: &'a DIFile,
@@ -1384,7 +1413,8 @@ extern "C" {
                                                   SizeInBits: u64,
                                                   AlignInBits: u32,
                                                   Elements: &'a DIArray,
-                                                  ClassType: &'a DIType)
+                                                  ClassType: &'a DIType,
+                                                  IsFixed: bool)
                                                   -> &'a DIType;
 
     pub fn LLVMRustDIBuilderCreateUnionType(Builder: &DIBuilder<'a>,
@@ -1400,6 +1430,19 @@ extern "C" {
                                             UniqueId: *const c_char)
                                             -> &'a DIType;
 
+    pub fn LLVMRustDIBuilderCreateVariantPart(Builder: &DIBuilder<'a>,
+                                              Scope: &'a DIScope,
+                                              Name: *const c_char,
+                                              File: &'a DIFile,
+                                              LineNo: c_uint,
+                                              SizeInBits: u64,
+                                              AlignInBits: u32,
+                                              Flags: DIFlags,
+                                              Discriminator: Option<&'a DIDerivedType>,
+                                              Elements: &'a DIArray,
+                                              UniqueId: *const c_char)
+                                              -> &'a DIDerivedType;
+
     pub fn LLVMSetUnnamedAddr(GlobalVar: &Value, UnnamedAddr: Bool);
 
     pub fn LLVMRustDIBuilderCreateTemplateTypeParameter(Builder: &DIBuilder<'a>,
@@ -1599,8 +1642,6 @@ extern "C" {
     pub fn LLVMRustModuleBufferFree(p: &'static mut ModuleBuffer);
     pub fn LLVMRustModuleCost(M: &Module) -> u64;
 
-    pub fn LLVMRustThinLTOAvailable() -> bool;
-    pub fn LLVMRustPGOAvailable() -> bool;
     pub fn LLVMRustThinLTOBufferCreate(M: &Module) -> &'static mut ThinLTOBuffer;
     pub fn LLVMRustThinLTOBufferFree(M: &'static mut ThinLTOBuffer);
     pub fn LLVMRustThinLTOBufferPtr(M: &ThinLTOBuffer) -> *const c_char;
diff --git a/src/librustc_codegen_llvm/llvm/mod.rs b/src/librustc_codegen_llvm/llvm/mod.rs
index 4343c8c184e..fbd5192a63f 100644
--- a/src/librustc_codegen_llvm/llvm/mod.rs
+++ b/src/librustc_codegen_llvm/llvm/mod.rs
@@ -190,7 +190,7 @@ impl ObjectFile {
     pub fn new(llmb: &'static mut MemoryBuffer) -> Option<ObjectFile> {
         unsafe {
             let llof = LLVMCreateObjectFile(llmb)?;
-            Some(ObjectFile { llof: llof })
+            Some(ObjectFile { llof })
         }
     }
 }
diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs
index 0a80fdddbf9..267d7e0d54b 100644
--- a/src/librustc_codegen_llvm/llvm_util.rs
+++ b/src/librustc_codegen_llvm/llvm_util.rs
@@ -184,7 +184,7 @@ const WASM_WHITELIST: &[(&str, Option<&str>)] = &[
 ];
 
 /// When rustdoc is running, provide a list of all known features so that all their respective
-/// primtives may be documented.
+/// primitives may be documented.
 ///
 /// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this
 /// iterator!
@@ -243,7 +243,8 @@ pub fn target_feature_whitelist(sess: &Session)
         "hexagon" => HEXAGON_WHITELIST,
         "mips" | "mips64" => MIPS_WHITELIST,
         "powerpc" | "powerpc64" => POWERPC_WHITELIST,
-        "wasm32" => WASM_WHITELIST,
+        // wasm32 on emscripten does not support these target features
+        "wasm32" if !sess.target.target.options.is_like_emscripten => WASM_WHITELIST,
         _ => &[],
     }
 }
@@ -256,6 +257,10 @@ pub fn print_version() {
     }
 }
 
+pub fn get_major_version() -> u32 {
+    unsafe { llvm::LLVMRustVersionMajor() }
+}
+
 pub fn print_passes() {
     // Can be called without initializing LLVM
     unsafe { llvm::LLVMRustPrintPasses(); }
diff --git a/src/librustc_codegen_llvm/meth.rs b/src/librustc_codegen_llvm/meth.rs
index 29c2e71960c..0dc5a4ddde8 100644
--- a/src/librustc_codegen_llvm/meth.rs
+++ b/src/librustc_codegen_llvm/meth.rs
@@ -39,7 +39,7 @@ impl<'a, 'tcx> VirtualIndex {
         // Load the data pointer from the object.
         debug!("get_fn({:?}, {:?})", llvtable, self);
 
-        let llvtable = bx.pointercast(llvtable, fn_ty.llvm_type(bx.cx).ptr_to().ptr_to());
+        let llvtable = bx.pointercast(llvtable, fn_ty.ptr_to_llvm_type(bx.cx).ptr_to());
         let ptr_align = bx.tcx().data_layout.pointer_align;
         let ptr = bx.load(bx.inbounds_gep(llvtable, &[C_usize(bx.cx, self.0)]), ptr_align);
         bx.nonnull_metadata(ptr);
@@ -89,7 +89,7 @@ pub fn get_vtable(
     let methods = tcx.vtable_methods(trait_ref.with_self_ty(tcx, ty));
     let methods = methods.iter().cloned().map(|opt_mth| {
         opt_mth.map_or(nullptr, |(def_id, substs)| {
-            callee::resolve_and_get_fn(cx, def_id, substs)
+            callee::resolve_and_get_fn_for_vtable(cx, def_id, substs)
         })
     });
 
diff --git a/src/librustc_codegen_llvm/mir/analyze.rs b/src/librustc_codegen_llvm/mir/analyze.rs
index a0d6cc46295..2af772bd7ce 100644
--- a/src/librustc_codegen_llvm/mir/analyze.rs
+++ b/src/librustc_codegen_llvm/mir/analyze.rs
@@ -15,7 +15,7 @@ use rustc_data_structures::bit_set::BitSet;
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use rustc::mir::{self, Location, TerminatorKind};
-use rustc::mir::visit::{Visitor, PlaceContext};
+use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext};
 use rustc::mir::traversal;
 use rustc::ty;
 use rustc::ty::layout::LayoutOf;
@@ -116,7 +116,11 @@ impl Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'll, 'tcx> {
                 self.not_ssa(index);
             }
         } else {
-            self.visit_place(place, PlaceContext::Store, location);
+            self.visit_place(
+                place,
+                PlaceContext::MutatingUse(MutatingUseContext::Store),
+                location
+            );
         }
 
         self.visit_rvalue(rvalue, location);
@@ -142,7 +146,11 @@ impl Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'll, 'tcx> {
                 // is not guaranteed to be statically dominated by the
                 // definition of x, so x must always be in an alloca.
                 if let mir::Operand::Move(ref place) = args[0] {
-                    self.visit_place(place, PlaceContext::Drop, location);
+                    self.visit_place(
+                        place,
+                        PlaceContext::MutatingUse(MutatingUseContext::Drop),
+                        location
+                    );
                 }
             }
         }
@@ -160,7 +168,8 @@ impl Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'll, 'tcx> {
         if let mir::Place::Projection(ref proj) = *place {
             // Allow uses of projections that are ZSTs or from scalar fields.
             let is_consume = match context {
-                PlaceContext::Copy | PlaceContext::Move => true,
+                PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
+                PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => true,
                 _ => false
             };
             if is_consume {
@@ -168,7 +177,9 @@ impl Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'll, 'tcx> {
                 let base_ty = self.fx.monomorphize(&base_ty);
 
                 // ZSTs don't require any actual memory access.
-                let elem_ty = base_ty.projection_ty(cx.tcx, &proj.elem).to_ty(cx.tcx);
+                let elem_ty = base_ty
+                    .projection_ty(cx.tcx, &proj.elem)
+                    .to_ty(cx.tcx);
                 let elem_ty = self.fx.monomorphize(&elem_ty);
                 if cx.layout_of(elem_ty).is_zst() {
                     return;
@@ -188,7 +199,11 @@ impl Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'll, 'tcx> {
 
             // A deref projection only reads the pointer, never needs the place.
             if let mir::ProjectionElem::Deref = proj.elem {
-                return self.visit_place(&proj.base, PlaceContext::Copy, location);
+                return self.visit_place(
+                    &proj.base,
+                    PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
+                    location
+                );
             }
         }
 
@@ -200,16 +215,15 @@ impl Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'll, 'tcx> {
                    context: PlaceContext<'tcx>,
                    location: Location) {
         match context {
-            PlaceContext::Call => {
+            PlaceContext::MutatingUse(MutatingUseContext::Call) => {
                 self.assign(local, location);
             }
 
-            PlaceContext::StorageLive |
-            PlaceContext::StorageDead |
-            PlaceContext::Validate => {}
+            PlaceContext::NonUse(_) |
+            PlaceContext::MutatingUse(MutatingUseContext::Retag) => {}
 
-            PlaceContext::Copy |
-            PlaceContext::Move => {
+            PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
+            PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => {
                 // Reads from uninitialized variables (e.g. in dead code, after
                 // optimizations) require locals to be in (uninitialized) memory.
                 // NB: there can be uninitialized reads of a local visited after
@@ -225,15 +239,19 @@ impl Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'll, 'tcx> {
                 }
             }
 
-            PlaceContext::Inspect |
-            PlaceContext::Store |
-            PlaceContext::AsmOutput |
-            PlaceContext::Borrow { .. } |
-            PlaceContext::Projection(..) => {
+            PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) |
+            PlaceContext::MutatingUse(MutatingUseContext::Store) |
+            PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) |
+            PlaceContext::MutatingUse(MutatingUseContext::Borrow(..)) |
+            PlaceContext::MutatingUse(MutatingUseContext::Projection) |
+            PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow(..)) |
+            PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow(..)) |
+            PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow(..)) |
+            PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => {
                 self.not_ssa(local);
             }
 
-            PlaceContext::Drop => {
+            PlaceContext::MutatingUse(MutatingUseContext::Drop) => {
                 let ty = mir::Place::Local(local).ty(self.fx.mir, self.fx.cx.tcx);
                 let ty = self.fx.monomorphize(&ty.to_ty(self.fx.cx.tcx));
 
@@ -328,7 +346,7 @@ pub fn cleanup_kinds<'a, 'tcx>(mir: &mir::Mir<'tcx>) -> IndexVec<mir::BasicBlock
                        funclet, succ, kind);
                 match kind {
                     CleanupKind::NotCleanup => {
-                        result[succ] = CleanupKind::Internal { funclet: funclet };
+                        result[succ] = CleanupKind::Internal { funclet };
                     }
                     CleanupKind::Funclet => {
                         if funclet != succ {
diff --git a/src/librustc_codegen_llvm/mir/block.rs b/src/librustc_codegen_llvm/mir/block.rs
index 68e30227185..3f9921a5cf9 100644
--- a/src/librustc_codegen_llvm/mir/block.rs
+++ b/src/librustc_codegen_llvm/mir/block.rs
@@ -298,8 +298,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
                 };
                 let (drop_fn, fn_ty) = match ty.sty {
                     ty::Dynamic(..) => {
-                        let fn_ty = drop_fn.ty(bx.cx.tcx);
-                        let sig = common::ty_fn_sig(bx.cx, fn_ty);
+                        let sig = drop_fn.fn_sig(bx.cx.tcx);
                         let sig = bx.tcx().normalize_erasing_late_bound_regions(
                             ty::ParamEnv::reveal_all(),
                             &sig,
@@ -643,14 +642,54 @@ impl FunctionCx<'a, 'll, 'tcx> {
                     (&args[..], None)
                 };
 
-                for (i, arg) in first_args.iter().enumerate() {
+                'make_args: for (i, arg) in first_args.iter().enumerate() {
                     let mut op = self.codegen_operand(&bx, arg);
+
                     if let (0, Some(ty::InstanceDef::Virtual(_, idx))) = (i, def) {
-                        if let Pair(data_ptr, meta) = op.val {
+                        if let Pair(..) = op.val {
+                            // In the case of Rc<Self>, we need to explicitly pass a
+                            // *mut RcBox<Self> with a Scalar (not ScalarPair) ABI. This is a hack
+                            // that is understood elsewhere in the compiler as a method on
+                            // `dyn Trait`.
+                            // To get a `*mut RcBox<Self>`, we just keep unwrapping newtypes until
+                            // we get a value of a built-in pointer type
+                            'descend_newtypes: while !op.layout.ty.is_unsafe_ptr()
+                                            && !op.layout.ty.is_region_ptr()
+                            {
+                                'iter_fields: for i in 0..op.layout.fields.count() {
+                                    let field = op.extract_field(&bx, i);
+                                    if !field.layout.is_zst() {
+                                        // we found the one non-zero-sized field that is allowed
+                                        // now find *its* non-zero-sized field, or stop if it's a
+                                        // pointer
+                                        op = field;
+                                        continue 'descend_newtypes
+                                    }
+                                }
+
+                                span_bug!(span, "receiver has no non-zero-sized fields {:?}", op);
+                            }
+
+                            // now that we have `*dyn Trait` or `&dyn Trait`, split it up into its
+                            // data pointer and vtable. Look up the method in the vtable, and pass
+                            // the data pointer as the first argument
+                            match op.val {
+                                Pair(data_ptr, meta) => {
+                                    llfn = Some(meth::VirtualIndex::from_index(idx)
+                                        .get_fn(&bx, meta, &fn_ty));
+                                    llargs.push(data_ptr);
+                                    continue 'make_args
+                                }
+                                other => bug!("expected a Pair, got {:?}", other)
+                            }
+                        } else if let Ref(data_ptr, Some(meta), _) = op.val {
+                            // by-value dynamic dispatch
                             llfn = Some(meth::VirtualIndex::from_index(idx)
                                 .get_fn(&bx, meta, &fn_ty));
                             llargs.push(data_ptr);
                             continue;
+                        } else {
+                            span_bug!(span, "can't codegen a virtual call on {:?}", op);
                         }
                     }
 
@@ -745,7 +784,8 @@ impl FunctionCx<'a, 'll, 'tcx> {
                     // have scary latent bugs around.
 
                     let scratch = PlaceRef::alloca(bx, arg.layout, "arg");
-                    base::memcpy_ty(bx, scratch.llval, llval, op.layout, align, MemFlags::empty());
+                    base::memcpy_ty(bx, scratch.llval, scratch.align, llval, align,
+                                    op.layout, MemFlags::empty());
                     (scratch.llval, scratch.align, true)
                 } else {
                     (llval, align, true)
diff --git a/src/librustc_codegen_llvm/mir/constant.rs b/src/librustc_codegen_llvm/mir/constant.rs
index 9f0f7443890..586a4907740 100644
--- a/src/librustc_codegen_llvm/mir/constant.rs
+++ b/src/librustc_codegen_llvm/mir/constant.rs
@@ -9,12 +9,11 @@
 // except according to those terms.
 
 use llvm;
-use rustc::mir::interpret::{ConstEvalErr, read_target_uint};
+use rustc::mir::interpret::{ErrorHandled, read_target_uint};
 use rustc_mir::const_eval::const_field;
 use rustc::hir::def_id::DefId;
 use rustc::mir;
 use rustc_data_structures::indexed_vec::Idx;
-use rustc_data_structures::sync::Lrc;
 use rustc::mir::interpret::{GlobalId, Pointer, Scalar, Allocation, ConstValue, AllocType};
 use rustc::ty::{self, Ty};
 use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Size};
@@ -88,8 +87,8 @@ pub fn scalar_to_llvm(
 
 pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll Value {
     let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1);
-    let layout = cx.data_layout();
-    let pointer_size = layout.pointer_size.bytes() as usize;
+    let dl = cx.data_layout();
+    let pointer_size = dl.pointer_size.bytes() as usize;
 
     let mut next_offset = 0;
     for &(offset, ((), alloc_id)) in alloc.relocations.iter() {
@@ -100,7 +99,7 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll
             llvals.push(C_bytes(cx, &alloc.bytes[next_offset..offset]));
         }
         let ptr_offset = read_target_uint(
-            layout.endian,
+            dl.endian,
             &alloc.bytes[offset..(offset + pointer_size)],
         ).expect("const_alloc_to_llvm: could not read relocation pointer") as u64;
         llvals.push(scalar_to_llvm(
@@ -124,7 +123,7 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll
 pub fn codegen_static_initializer(
     cx: &CodegenCx<'ll, 'tcx>,
     def_id: DefId,
-) -> Result<(&'ll Value, &'tcx Allocation), Lrc<ConstEvalErr<'tcx>>> {
+) -> Result<(&'ll Value, &'tcx Allocation), ErrorHandled> {
     let instance = ty::Instance::mono(cx.tcx, def_id);
     let cid = GlobalId {
         instance,
@@ -145,7 +144,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
         &mut self,
         bx: &Builder<'a, 'll, 'tcx>,
         constant: &'tcx ty::Const<'tcx>,
-    ) -> Result<&'tcx ty::Const<'tcx>, Lrc<ConstEvalErr<'tcx>>> {
+    ) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> {
         match constant.val {
             ConstValue::Unevaluated(def_id, ref substs) => {
                 let tcx = bx.tcx();
@@ -165,7 +164,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
         &mut self,
         bx: &Builder<'a, 'll, 'tcx>,
         constant: &mir::Constant<'tcx>,
-    ) -> Result<&'tcx ty::Const<'tcx>, Lrc<ConstEvalErr<'tcx>>> {
+    ) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> {
         let c = self.monomorphize(&constant.literal);
         self.fully_evaluate(bx, c)
     }
@@ -176,7 +175,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
         bx: &Builder<'a, 'll, 'tcx>,
         span: Span,
         ty: Ty<'tcx>,
-        constant: Result<&'tcx ty::Const<'tcx>, Lrc<ConstEvalErr<'tcx>>>,
+        constant: Result<&'tcx ty::Const<'tcx>, ErrorHandled>,
     ) -> (&'ll Value, Ty<'tcx>) {
         constant
             .and_then(|c| {
@@ -185,7 +184,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
                     ty::Array(_, n) => n.unwrap_usize(bx.tcx()),
                     ref other => bug!("invalid simd shuffle type: {}", other),
                 };
-                let values: Result<Vec<_>, Lrc<_>> = (0..fields).map(|field| {
+                let values: Result<Vec<_>, ErrorHandled> = (0..fields).map(|field| {
                     let field = const_field(
                         bx.tcx(),
                         ty::ParamEnv::reveal_all(),
@@ -211,9 +210,9 @@ impl FunctionCx<'a, 'll, 'tcx> {
                 let llval = C_struct(bx.cx, &values?, false);
                 Ok((llval, c.ty))
             })
-            .unwrap_or_else(|e| {
-                e.report_as_error(
-                    bx.tcx().at(span),
+            .unwrap_or_else(|_| {
+                bx.tcx().sess.span_err(
+                    span,
                     "could not evaluate shuffle_indices at compile time",
                 );
                 // We've errored, so we don't have to produce working code.
diff --git a/src/librustc_codegen_llvm/mir/mod.rs b/src/librustc_codegen_llvm/mir/mod.rs
index a6e2ccf92e4..e5b25ea068b 100644
--- a/src/librustc_codegen_llvm/mir/mod.rs
+++ b/src/librustc_codegen_llvm/mir/mod.rs
@@ -12,6 +12,7 @@ use common::{C_i32, C_null};
 use libc::c_uint;
 use llvm::{self, BasicBlock};
 use llvm::debuginfo::DIScope;
+use llvm_util;
 use rustc::ty::{self, Ty, TypeFoldable, UpvarSubsts};
 use rustc::ty::layout::{LayoutOf, TyLayout};
 use rustc::mir::{self, Mir};
@@ -612,7 +613,7 @@ fn arg_local_refs(
             // doesn't actually strip the offset when splitting the closure
             // environment into its components so it ends up out of bounds.
             // (cuviper) It seems to be fine without the alloca on LLVM 6 and later.
-            let env_alloca = !env_ref && unsafe { llvm::LLVMRustVersionMajor() < 6 };
+            let env_alloca = !env_ref && llvm_util::get_major_version() < 6;
             let env_ptr = if env_alloca {
                 let scratch = PlaceRef::alloca(bx,
                     bx.cx.layout_of(tcx.mk_mut_ptr(arg.layout.ty)),
diff --git a/src/librustc_codegen_llvm/mir/operand.rs b/src/librustc_codegen_llvm/mir/operand.rs
index ab43531240f..c76cbfcd971 100644
--- a/src/librustc_codegen_llvm/mir/operand.rs
+++ b/src/librustc_codegen_llvm/mir/operand.rs
@@ -8,11 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::mir::interpret::{ConstValue, ConstEvalErr};
+use rustc::mir::interpret::{ConstValue, ErrorHandled};
 use rustc::mir;
 use rustc::ty;
 use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
-use rustc_data_structures::sync::Lrc;
 
 use base;
 use common::{CodegenCx, C_undef, C_usize};
@@ -79,7 +78,7 @@ impl OperandRef<'ll, 'tcx> {
 
     pub fn from_const(bx: &Builder<'a, 'll, 'tcx>,
                       val: &'tcx ty::Const<'tcx>)
-                      -> Result<OperandRef<'ll, 'tcx>, Lrc<ConstEvalErr<'tcx>>> {
+                      -> Result<OperandRef<'ll, 'tcx>, ErrorHandled> {
         let layout = bx.cx.layout_of(val.ty);
 
         if layout.is_zst() {
@@ -283,8 +282,8 @@ impl OperandValue<'ll> {
         }
         match self {
             OperandValue::Ref(r, None, source_align) => {
-                base::memcpy_ty(bx, dest.llval, r, dest.layout,
-                                source_align.min(dest.align), flags)
+                base::memcpy_ty(bx, dest.llval, dest.align, r, source_align,
+                                dest.layout, flags)
             }
             OperandValue::Ref(_, Some(_), _) => {
                 bug!("cannot directly store unsized values");
@@ -325,7 +324,7 @@ impl OperandValue<'ll> {
         // Allocate an appropriate region on the stack, and copy the value into it
         let (llsize, _) = glue::size_and_align_of_dst(&bx, unsized_ty, Some(llextra));
         let lldst = bx.array_alloca(Type::i8(bx.cx), llsize, "unsized_tmp", max_align);
-        base::call_memcpy(&bx, lldst, llptr, llsize, min_align, flags);
+        base::call_memcpy(&bx, lldst, max_align, llptr, min_align, llsize, flags);
 
         // Store the allocated region and the extra to the indirect place.
         let indirect_operand = OperandValue::Pair(lldst, llextra);
@@ -424,10 +423,13 @@ impl FunctionCx<'a, 'll, 'tcx> {
                 self.eval_mir_constant(bx, constant)
                     .and_then(|c| OperandRef::from_const(bx, c))
                     .unwrap_or_else(|err| {
-                        err.report_as_error(
-                            bx.tcx().at(constant.span),
-                            "could not evaluate constant operand",
-                        );
+                        match err {
+                            // errored or at least linted
+                            ErrorHandled::Reported => {},
+                            ErrorHandled::TooGeneric => {
+                                bug!("codgen encountered polymorphic constant")
+                            },
+                        }
                         // Allow RalfJ to sleep soundly knowing that even refactorings that remove
                         // the above error (or silence it under some conditions) will not cause UB
                         let fnname = bx.cx.get_intrinsic(&("llvm.trap"));
diff --git a/src/librustc_codegen_llvm/mir/place.rs b/src/librustc_codegen_llvm/mir/place.rs
index e7b6f5908a4..75ec5ead243 100644
--- a/src/librustc_codegen_llvm/mir/place.rs
+++ b/src/librustc_codegen_llvm/mir/place.rs
@@ -10,7 +10,7 @@
 
 use llvm::{self, LLVMConstInBoundsGEP};
 use rustc::ty::{self, Ty};
-use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, Size};
+use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, Size, VariantIdx};
 use rustc::mir;
 use rustc::mir::tcx::PlaceTy;
 use base;
@@ -281,7 +281,7 @@ impl PlaceRef<'ll, 'tcx> {
         match self.layout.variants {
             layout::Variants::Single { index } => {
                 let discr_val = self.layout.ty.ty_adt_def().map_or(
-                    index as u128,
+                    index.as_u32() as u128,
                     |def| def.discriminant_for_variant(bx.cx.tcx, index).val);
                 return C_uint_big(cast_to, discr_val);
             }
@@ -320,16 +320,16 @@ impl PlaceRef<'ll, 'tcx> {
                         C_uint_big(niche_llty, niche_start)
                     };
                     bx.select(bx.icmp(llvm::IntEQ, lldiscr, niche_llval),
-                        C_uint(cast_to, *niche_variants.start() as u64),
-                        C_uint(cast_to, dataful_variant as u64))
+                        C_uint(cast_to, niche_variants.start().as_u32() as u64),
+                        C_uint(cast_to, dataful_variant.as_u32() as u64))
                 } else {
                     // Rebase from niche values to discriminant values.
-                    let delta = niche_start.wrapping_sub(*niche_variants.start() as u128);
+                    let delta = niche_start.wrapping_sub(niche_variants.start().as_u32() as u128);
                     let lldiscr = bx.sub(lldiscr, C_uint_big(niche_llty, delta));
-                    let lldiscr_max = C_uint(niche_llty, *niche_variants.end() as u64);
+                    let lldiscr_max = C_uint(niche_llty, niche_variants.end().as_u32() as u64);
                     bx.select(bx.icmp(llvm::IntULE, lldiscr, lldiscr_max),
                         bx.intcast(lldiscr, cast_to, false),
-                        C_uint(cast_to, dataful_variant as u64))
+                        C_uint(cast_to, dataful_variant.as_u32() as u64))
                 }
             }
         }
@@ -337,7 +337,7 @@ impl PlaceRef<'ll, 'tcx> {
 
     /// Set the discriminant for a new value of the given case of the given
     /// representation.
-    pub fn codegen_set_discr(&self, bx: &Builder<'a, 'll, 'tcx>, variant_index: usize) {
+    pub fn codegen_set_discr(&self, bx: &Builder<'a, 'll, 'tcx>, variant_index: VariantIdx) {
         if self.layout.for_variant(bx.cx, variant_index).abi.is_uninhabited() {
             return;
         }
@@ -376,7 +376,8 @@ impl PlaceRef<'ll, 'tcx> {
 
                     let niche = self.project_field(bx, 0);
                     let niche_llty = niche.layout.immediate_llvm_type(bx.cx);
-                    let niche_value = ((variant_index - *niche_variants.start()) as u128)
+                    let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
+                    let niche_value = (niche_value as u128)
                         .wrapping_add(niche_start);
                     // FIXME(eddyb) Check the actual primitive type here.
                     let niche_llval = if niche_value == 0 {
@@ -401,7 +402,7 @@ impl PlaceRef<'ll, 'tcx> {
         }
     }
 
-    pub fn project_downcast(&self, bx: &Builder<'a, 'll, 'tcx>, variant_index: usize)
+    pub fn project_downcast(&self, bx: &Builder<'a, 'll, 'tcx>, variant_index: VariantIdx)
                             -> PlaceRef<'ll, 'tcx> {
         let mut downcast = *self;
         downcast.layout = self.layout.for_variant(bx.cx, variant_index);
@@ -517,7 +518,8 @@ impl FunctionCx<'a, 'll, 'tcx> {
                         let mut subslice = cg_base.project_index(bx,
                             C_usize(bx.cx, from as u64));
                         let projected_ty = PlaceTy::Ty { ty: cg_base.layout.ty }
-                            .projection_ty(tcx, &projection.elem).to_ty(bx.tcx());
+                            .projection_ty(tcx, &projection.elem)
+                            .to_ty(bx.tcx());
                         subslice.layout = bx.cx.layout_of(self.monomorphize(&projected_ty));
 
                         if subslice.layout.is_unsized() {
diff --git a/src/librustc_codegen_llvm/mir/statement.rs b/src/librustc_codegen_llvm/mir/statement.rs
index 93be0074f6e..8bda2c98594 100644
--- a/src/librustc_codegen_llvm/mir/statement.rs
+++ b/src/librustc_codegen_llvm/mir/statement.rs
@@ -84,21 +84,18 @@ impl FunctionCx<'a, 'll, 'tcx> {
                 }).collect();
 
                 let input_vals = inputs.iter()
-                    .try_fold(Vec::with_capacity(inputs.len()), |mut acc, input| {
+                    .fold(Vec::with_capacity(inputs.len()), |mut acc, (span, input)| {
                         let op = self.codegen_operand(&bx, input);
                         if let OperandValue::Immediate(_) = op.val {
                             acc.push(op.immediate());
-                            Ok(acc)
                         } else {
-                            Err(op)
+                            span_err!(bx.sess(), span.to_owned(), E0669,
+                                     "invalid value for constraint in inline assembly");
                         }
+                        acc
                 });
 
-                if input_vals.is_err() {
-                   span_err!(bx.sess(), statement.source_info.span, E0669,
-                             "invalid value for constraint in inline assembly");
-                } else {
-                    let input_vals = input_vals.unwrap();
+                if input_vals.len() == inputs.len() {
                     let res = asm::codegen_inline_asm(&bx, asm, outputs, input_vals);
                     if !res {
                         span_err!(bx.sess(), statement.source_info.span, E0668,
@@ -108,8 +105,9 @@ impl FunctionCx<'a, 'll, 'tcx> {
                 bx
             }
             mir::StatementKind::FakeRead(..) |
-            mir::StatementKind::EndRegion(_) |
-            mir::StatementKind::Validate(..) |
+            mir::StatementKind::EndRegion(..) |
+            mir::StatementKind::Retag { .. } |
+            mir::StatementKind::EscapeToRaw { .. } |
             mir::StatementKind::AscribeUserType(..) |
             mir::StatementKind::Nop => bx,
         }
diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs
index dab9b147cc0..91c1ccbe002 100644
--- a/src/librustc_codegen_llvm/mono_item.rs
+++ b/src/librustc_codegen_llvm/mono_item.rs
@@ -153,9 +153,9 @@ fn predefine_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
     assert!(!instance.substs.needs_infer() &&
             !instance.substs.has_param_types());
 
-    let mono_ty = instance.ty(cx.tcx);
+    let mono_sig = instance.fn_sig(cx.tcx);
     let attrs = cx.tcx.codegen_fn_attrs(instance.def_id());
-    let lldecl = declare::declare_fn(cx, symbol_name, mono_ty);
+    let lldecl = declare::declare_fn(cx, symbol_name, mono_sig);
     unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) };
     base::set_link_section(lldecl, &attrs);
     if linkage == Linkage::LinkOnceODR ||
@@ -178,7 +178,7 @@ fn predefine_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
         }
     }
 
-    debug!("predefine_fn: mono_ty = {:?} instance = {:?}", mono_ty, instance);
+    debug!("predefine_fn: mono_sig = {:?} instance = {:?}", mono_sig, instance);
     if instance.def.is_inline(cx.tcx) {
         attributes::inline(cx, lldecl, attributes::InlineAttr::Hint);
     }
diff --git a/src/librustc_codegen_llvm/type_.rs b/src/librustc_codegen_llvm/type_.rs
index 51a233d7916..6fb78fe4aa5 100644
--- a/src/librustc_codegen_llvm/type_.rs
+++ b/src/librustc_codegen_llvm/type_.rs
@@ -234,6 +234,8 @@ impl Type {
     }
 
     pub fn ptr_to(&self) -> &Type {
+        assert_ne!(self.kind(), TypeKind::Function,
+                   "don't call ptr_to on function types, use ptr_to_llvm_type on FnType instead");
         unsafe {
             llvm::LLVMPointerType(self, 0)
         }
diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs
index 03ded64e642..fea02edf7be 100644
--- a/src/librustc_codegen_llvm/type_of.rs
+++ b/src/librustc_codegen_llvm/type_of.rs
@@ -265,7 +265,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
                         ty::ParamEnv::reveal_all(),
                         &sig,
                     );
-                    FnType::new(cx, sig, &[]).llvm_type(cx).ptr_to()
+                    FnType::new(cx, sig, &[]).ptr_to_llvm_type(cx)
                 }
                 _ => self.scalar_llvm_type_at(cx, scalar, Size::ZERO)
             };
@@ -285,7 +285,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
 
         debug!("llvm_type({:#?})", self);
 
-        assert!(!self.ty.has_escaping_regions(), "{:?} has escaping regions", self.ty);
+        assert!(!self.ty.has_escaping_bound_vars(), "{:?} has escaping bound vars", self.ty);
 
         // Make sure lifetimes are erased, to avoid generating distinct LLVM
         // types for Rust types that only differ in the choice of lifetimes.