about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-08-17 21:24:22 +0000
committerbors <bors@rust-lang.org>2018-08-17 21:24:22 +0000
commit1fa944914c092d728c8307e976a4b447df25bf16 (patch)
treeb61dd57fb983082285f9d301c028ae305d391ffe /src
parentc8c587fe4ea43afb1c3cf9fe008101f09003ccd1 (diff)
parentd662083a6c78928c70cc74b600205c246dab3bf6 (diff)
downloadrust-1fa944914c092d728c8307e976a4b447df25bf16.tar.gz
rust-1fa944914c092d728c8307e976a4b447df25bf16.zip
Auto merge of #53356 - michaelwoerister:itlto, r=alexcrichton
Preliminary work for incremental ThinLTO (CGU name edition)

Bring back the first half of #52266 but hopefully without the performance regression.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/mir/mono.rs97
-rw-r--r--src/librustc/session/mod.rs10
-rw-r--r--src/librustc_codegen_llvm/back/link.rs7
-rw-r--r--src/librustc_codegen_llvm/back/lto.rs11
-rw-r--r--src/librustc_codegen_llvm/back/write.rs3
-rw-r--r--src/librustc_codegen_llvm/base.rs67
-rw-r--r--src/librustc_codegen_llvm/lib.rs4
-rw-r--r--src/librustc_incremental/assert_module_sources.rs55
-rw-r--r--src/librustc_mir/monomorphize/partitioning.rs142
-rw-r--r--src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs6
-rw-r--r--src/test/codegen-units/item-collection/generic-drop-glue.rs12
-rw-r--r--src/test/codegen-units/item-collection/instantiation-through-vtable.rs4
-rw-r--r--src/test/codegen-units/item-collection/non-generic-drop-glue.rs4
-rw-r--r--src/test/codegen-units/item-collection/transitive-drop-glue.rs18
-rw-r--r--src/test/codegen-units/item-collection/tuple-drop-glue.rs8
-rw-r--r--src/test/codegen-units/item-collection/unsizing.rs8
-rw-r--r--src/test/incremental/issue-39828/auxiliary/generic.rs2
-rw-r--r--src/test/run-make-fulldeps/cross-lang-lto/Makefile8
-rw-r--r--src/test/run-make-fulldeps/extra-filename-with-temp-outputs/Makefile2
-rw-r--r--src/test/ui/lto-duplicate-symbols.stderr2
-rw-r--r--src/tools/compiletest/src/runtest.rs33
21 files changed, 331 insertions, 172 deletions
diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs
index f0d6b8170eb..9d2f62bd030 100644
--- a/src/librustc/mir/mono.rs
+++ b/src/librustc/mir/mono.rs
@@ -8,15 +8,16 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use hir::def_id::DefId;
+use hir::def_id::{DefId, CrateNum};
 use syntax::ast::NodeId;
-use syntax::symbol::InternedString;
+use syntax::symbol::{Symbol, InternedString};
 use ty::{Instance, TyCtxt};
 use util::nodemap::FxHashMap;
 use rustc_data_structures::base_n;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasherResult,
                                            StableHasher};
 use ich::{Fingerprint, StableHashingContext, NodeIdHashingMode};
+use std::fmt;
 use std::hash::Hash;
 
 #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
@@ -239,3 +240,95 @@ impl Stats {
         self.fn_stats.extend(stats.fn_stats);
     }
 }
+
+pub struct CodegenUnitNameBuilder<'a, 'gcx: 'tcx, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'gcx, 'tcx>,
+    cache: FxHashMap<CrateNum, String>,
+}
+
+impl<'a, 'gcx: 'tcx, 'tcx: 'a> CodegenUnitNameBuilder<'a, 'gcx, 'tcx> {
+
+    pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self {
+        CodegenUnitNameBuilder {
+            tcx,
+            cache: FxHashMap(),
+        }
+    }
+
+    /// CGU names should fulfill the following requirements:
+    /// - They should be able to act as a file name on any kind of file system
+    /// - They should not collide with other CGU names, even for different versions
+    ///   of the same crate.
+    ///
+    /// Consequently, we don't use special characters except for '.' and '-' and we
+    /// prefix each name with the crate-name and crate-disambiguator.
+    ///
+    /// This function will build CGU names of the form:
+    ///
+    /// ```
+    /// <crate-name>.<crate-disambiguator>(-<component>)*[.<special-suffix>]
+    /// ```
+    ///
+    /// The '.' before `<special-suffix>` makes sure that names with a special
+    /// suffix can never collide with a name built out of regular Rust
+    /// identifiers (e.g. module paths).
+    pub fn build_cgu_name<I, C, S>(&mut self,
+                                   cnum: CrateNum,
+                                   components: I,
+                                   special_suffix: Option<S>)
+                                   -> InternedString
+        where I: IntoIterator<Item=C>,
+              C: fmt::Display,
+              S: fmt::Display,
+    {
+        let cgu_name = self.build_cgu_name_no_mangle(cnum,
+                                                     components,
+                                                     special_suffix);
+
+        if self.tcx.sess.opts.debugging_opts.human_readable_cgu_names {
+            cgu_name
+        } else {
+            let cgu_name = &cgu_name.as_str()[..];
+            Symbol::intern(&CodegenUnit::mangle_name(cgu_name)).as_interned_str()
+        }
+    }
+
+    /// Same as `CodegenUnit::build_cgu_name()` but will never mangle the
+    /// resulting name.
+    pub fn build_cgu_name_no_mangle<I, C, S>(&mut self,
+                                             cnum: CrateNum,
+                                             components: I,
+                                             special_suffix: Option<S>)
+                                             -> InternedString
+        where I: IntoIterator<Item=C>,
+              C: fmt::Display,
+              S: fmt::Display,
+    {
+        use std::fmt::Write;
+
+        let mut cgu_name = String::with_capacity(64);
+
+        // Start out with the crate name and disambiguator
+        let tcx = self.tcx;
+        let crate_prefix = self.cache.entry(cnum).or_insert_with(|| {
+            let crate_disambiguator = format!("{}", tcx.crate_disambiguator(cnum));
+            // Using a shortened disambiguator of about 40 bits
+            format!("{}.{}", tcx.crate_name(cnum), &crate_disambiguator[0 .. 8])
+        });
+
+        write!(cgu_name, "{}", crate_prefix).unwrap();
+
+        // Add the components
+        for component in components {
+            write!(cgu_name, "-{}", component).unwrap();
+        }
+
+        if let Some(special_suffix) = special_suffix {
+            // We add a dot in here so it cannot clash with anything in a regular
+            // Rust identifier
+            write!(cgu_name, ".{}", special_suffix).unwrap();
+        }
+
+        Symbol::intern(&cgu_name[..]).as_interned_str()
+    }
+}
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index f474f214305..3dc697e6adb 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -24,6 +24,7 @@ use util::nodemap::{FxHashMap, FxHashSet};
 use util::common::{duration_to_secs_str, ErrorReported};
 use util::common::ProfileQueriesMsg;
 
+use rustc_data_structures::base_n;
 use rustc_data_structures::sync::{self, Lrc, Lock, LockCell, OneThread, Once, RwLock};
 
 use syntax::ast::NodeId;
@@ -48,6 +49,7 @@ use std;
 use std::cell::{self, Cell, RefCell};
 use std::collections::HashMap;
 use std::env;
+use std::fmt;
 use std::io::Write;
 use std::path::{Path, PathBuf};
 use std::time::Duration;
@@ -1221,6 +1223,14 @@ impl CrateDisambiguator {
     }
 }
 
+impl fmt::Display for CrateDisambiguator {
+    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+        let (a, b) = self.0.as_value();
+        let as_u128 = a as u128 | ((b as u128) << 64);
+        f.write_str(&base_n::encode(as_u128, base_n::CASE_INSENSITIVE))
+    }
+}
+
 impl From<Fingerprint> for CrateDisambiguator {
     fn from(fingerprint: Fingerprint) -> CrateDisambiguator {
         CrateDisambiguator(fingerprint)
diff --git a/src/librustc_codegen_llvm/back/link.rs b/src/librustc_codegen_llvm/back/link.rs
index bbe1ccf3696..37c99932f56 100644
--- a/src/librustc_codegen_llvm/back/link.rs
+++ b/src/librustc_codegen_llvm/back/link.rs
@@ -46,13 +46,6 @@ use std::process::{Output, Stdio};
 use std::str;
 use syntax::attr;
 
-/// The LLVM module name containing crate-metadata. This includes a `.` on
-/// purpose, so it cannot clash with the name of a user-defined module.
-pub const METADATA_MODULE_NAME: &'static str = "crate.metadata";
-
-// same as for metadata above, but for allocator shim
-pub const ALLOCATOR_MODULE_NAME: &'static str = "crate.allocator";
-
 pub use rustc_codegen_utils::link::{find_crate_name, filename_for_input, default_output_for_target,
                                   invalid_output_for_target, build_link_meta, out_filename,
                                   check_file_is_writeable};
diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs
index d7741230327..56858a31efd 100644
--- a/src/librustc_codegen_llvm/back/lto.rs
+++ b/src/librustc_codegen_llvm/back/lto.rs
@@ -242,7 +242,7 @@ fn fat_lto(cgcx: &CodegenContext,
             let llvm = module.llvm().expect("can't lto pre-codegened modules");
             (&llvm.llcx, llvm.llmod())
         };
-        info!("using {:?} as a base module", module.llmod_id);
+        info!("using {:?} as a base module", module.name);
 
         // The linking steps below may produce errors and diagnostics within LLVM
         // which we'd like to handle and print, so set up our diagnostic handlers
@@ -257,7 +257,7 @@ fn fat_lto(cgcx: &CodegenContext,
         for module in modules {
             let llvm = module.llvm().expect("can't lto pre-codegened modules");
             let buffer = ModuleBuffer::new(llvm.llmod());
-            let llmod_id = CString::new(&module.llmod_id[..]).unwrap();
+            let llmod_id = CString::new(&module.name[..]).unwrap();
             serialized_modules.push((SerializedModule::Local(buffer), llmod_id));
         }
 
@@ -384,9 +384,9 @@ fn thin_lto(diag_handler: &Handler,
         //        the most expensive portion of this small bit of global
         //        analysis!
         for (i, module) in modules.iter().enumerate() {
-            info!("local module: {} - {}", i, module.llmod_id);
+            info!("local module: {} - {}", i, module.name);
             let llvm = module.llvm().expect("can't lto precodegened module");
-            let name = CString::new(module.llmod_id.clone()).unwrap();
+            let name = CString::new(module.name.clone()).unwrap();
             let buffer = ThinBuffer::new(llvm.llmod());
             thin_modules.push(llvm::ThinLTOModule {
                 identifier: name.as_ptr(),
@@ -395,7 +395,7 @@ fn thin_lto(diag_handler: &Handler,
             });
             thin_buffers.push(buffer);
             module_names.push(name);
-            timeline.record(&module.llmod_id);
+            timeline.record(&module.name);
         }
 
         // FIXME: All upstream crates are deserialized internally in the
@@ -668,7 +668,6 @@ impl ThinModule {
                 llcx,
                 tm,
             }),
-            llmod_id: self.name().to_string(),
             name: self.name().to_string(),
             kind: ModuleKind::Regular,
         };
diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs
index d60983d7697..b62836ec255 100644
--- a/src/librustc_codegen_llvm/back/write.rs
+++ b/src/librustc_codegen_llvm/back/write.rs
@@ -728,7 +728,7 @@ unsafe fn codegen(cgcx: &CodegenContext,
 
             if config.emit_bc_compressed {
                 let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION);
-                let data = bytecode::encode(&module.llmod_id, data);
+                let data = bytecode::encode(&module.name, data);
                 if let Err(e) = fs::write(&dst, data) {
                     diag_handler.err(&format!("failed to write bytecode: {}", e));
                 }
@@ -1338,7 +1338,6 @@ fn execute_work_item(cgcx: &CodegenContext,
         assert_eq!(bytecode_compressed.is_some(), config.emit_bc_compressed);
 
         Ok(WorkItemResult::Compiled(CompiledModule {
-            llmod_id: module.llmod_id.clone(),
             name: module_name,
             kind: ModuleKind::Regular,
             pre_existing: true,
diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs
index 7ca6a89dd9b..e626cc3870f 100644
--- a/src/librustc_codegen_llvm/base.rs
+++ b/src/librustc_codegen_llvm/base.rs
@@ -36,7 +36,7 @@ use metadata;
 use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc::middle::lang_items::StartFnLangItem;
 use rustc::middle::weak_lang_items;
-use rustc::mir::mono::{Linkage, Visibility, Stats};
+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};
@@ -742,19 +742,23 @@ pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     let crate_hash = tcx.crate_hash(LOCAL_CRATE);
     let link_meta = link::build_link_meta(crate_hash);
+    let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
 
     // Codegen the metadata.
     tcx.sess.profiler(|p| p.start_activity(ProfileCategory::Codegen));
-    let llmod_id = "metadata";
-    let metadata_llvm_module = ModuleLlvm::new(tcx.sess, llmod_id);
+
+    let metadata_cgu_name = cgu_name_builder.build_cgu_name(LOCAL_CRATE,
+                                                            &["crate"],
+                                                            Some("metadata")).as_str()
+                                                                             .to_string();
+    let metadata_llvm_module = ModuleLlvm::new(tcx.sess, &metadata_cgu_name);
     let metadata = time(tcx.sess, "write metadata", || {
         write_metadata(tcx, &metadata_llvm_module, &link_meta)
     });
     tcx.sess.profiler(|p| p.end_activity(ProfileCategory::Codegen));
 
     let metadata_module = ModuleCodegen {
-        name: link::METADATA_MODULE_NAME.to_string(),
-        llmod_id: llmod_id.to_string(),
+        name: metadata_cgu_name,
         source: ModuleSource::Codegened(metadata_llvm_module),
         kind: ModuleKind::Metadata,
     };
@@ -833,20 +837,22 @@ pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let allocator_module = if any_dynamic_crate {
         None
     } else if let Some(kind) = *tcx.sess.allocator_kind.get() {
-        unsafe {
-            let llmod_id = "allocator";
-            let modules = ModuleLlvm::new(tcx.sess, llmod_id);
-            time(tcx.sess, "write allocator module", || {
+        let llmod_id = cgu_name_builder.build_cgu_name(LOCAL_CRATE,
+                                                       &["crate"],
+                                                       Some("allocator")).as_str()
+                                                                         .to_string();
+        let modules = ModuleLlvm::new(tcx.sess, &llmod_id);
+        time(tcx.sess, "write allocator module", || {
+            unsafe {
                 allocator::codegen(tcx, &modules, kind)
-            });
+            }
+        });
 
-            Some(ModuleCodegen {
-                name: link::ALLOCATOR_MODULE_NAME.to_string(),
-                llmod_id: llmod_id.to_string(),
-                source: ModuleSource::Codegened(modules),
-                kind: ModuleKind::Allocator,
-            })
-        }
+        Some(ModuleCodegen {
+            name: llmod_id,
+            source: ModuleSource::Codegened(modules),
+            kind: ModuleKind::Allocator,
+        })
     } else {
         None
     };
@@ -889,21 +895,10 @@ pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 // succeed it means that none of the dependencies has changed
                 // and we can safely re-use.
                 if let Some(dep_node_index) = tcx.dep_graph.try_mark_green(tcx, dep_node) {
-                    // Append ".rs" to LLVM module identifier.
-                    //
-                    // LLVM code generator emits a ".file filename" directive
-                    // for ELF backends. Value of the "filename" is set as the
-                    // LLVM module identifier.  Due to a LLVM MC bug[1], LLVM
-                    // crashes if the module identifier is same as other symbols
-                    // such as a function name in the module.
-                    // 1. http://llvm.org/bugs/show_bug.cgi?id=11479
-                    let llmod_id = format!("{}.rs", cgu.name());
-
                     let module = ModuleCodegen {
                         name: cgu.name().to_string(),
                         source: ModuleSource::Preexisting(buf),
                         kind: ModuleKind::Regular,
-                        llmod_id,
                     };
                     tcx.dep_graph.mark_loaded_from_cache(dep_node_index, true);
                     write::submit_codegened_module_to_llvm(tcx, module, 0);
@@ -1212,21 +1207,8 @@ fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     {
         let cgu_name = cgu.name().to_string();
 
-        // Append ".rs" to LLVM module identifier.
-        //
-        // LLVM code generator emits a ".file filename" directive
-        // for ELF backends. Value of the "filename" is set as the
-        // LLVM module identifier.  Due to a LLVM MC bug[1], LLVM
-        // crashes if the module identifier is same as other symbols
-        // such as a function name in the module.
-        // 1. http://llvm.org/bugs/show_bug.cgi?id=11479
-        let llmod_id = format!("{}-{}.rs",
-                               cgu.name(),
-                               tcx.crate_disambiguator(LOCAL_CRATE)
-                                   .to_fingerprint().to_hex());
-
         // Instantiate monomorphizations without filling out definitions yet...
-        let llvm_module = ModuleLlvm::new(tcx.sess, &llmod_id);
+        let llvm_module = ModuleLlvm::new(tcx.sess, &cgu_name);
         let stats = {
             let cx = CodegenCx::new(tcx, cgu, &llvm_module);
             let mono_items = cx.codegen_unit
@@ -1282,7 +1264,6 @@ fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             name: cgu_name,
             source: ModuleSource::Codegened(llvm_module),
             kind: ModuleKind::Regular,
-            llmod_id,
         })
     }
 }
diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs
index 390a1df02b8..a65511a24af 100644
--- a/src/librustc_codegen_llvm/lib.rs
+++ b/src/librustc_codegen_llvm/lib.rs
@@ -269,8 +269,8 @@ struct ModuleCodegen {
     /// unique amongst **all** crates.  Therefore, it should contain
     /// something unique to this crate (e.g., a module path) as well
     /// as the crate name and disambiguator.
+    /// We currently generate these names via CodegenUnit::build_cgu_name().
     name: String,
-    llmod_id: String,
     source: ModuleSource,
     kind: ModuleKind,
 }
@@ -317,7 +317,6 @@ impl ModuleCodegen {
         };
 
         CompiledModule {
-            llmod_id: self.llmod_id,
             name: self.name.clone(),
             kind: self.kind,
             pre_existing,
@@ -331,7 +330,6 @@ impl ModuleCodegen {
 #[derive(Debug)]
 struct CompiledModule {
     name: String,
-    llmod_id: String,
     kind: ModuleKind,
     pre_existing: bool,
     object: Option<PathBuf>,
diff --git a/src/librustc_incremental/assert_module_sources.rs b/src/librustc_incremental/assert_module_sources.rs
index df8e0f056af..9b8e2c450d5 100644
--- a/src/librustc_incremental/assert_module_sources.rs
+++ b/src/librustc_incremental/assert_module_sources.rs
@@ -27,11 +27,11 @@
 //! the HIR doesn't change as a result of the annotations, which might
 //! perturb the reuse results.
 
+use rustc::hir::def_id::LOCAL_CRATE;
 use rustc::dep_graph::{DepNode, DepConstructor};
-use rustc::mir::mono::CodegenUnit;
+use rustc::mir::mono::CodegenUnitNameBuilder;
 use rustc::ty::TyCtxt;
 use syntax::ast;
-use syntax_pos::symbol::Symbol;
 use rustc::ich::{ATTR_PARTITION_REUSED, ATTR_PARTITION_CODEGENED};
 
 const MODULE: &'static str = "module";
@@ -72,12 +72,37 @@ impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> {
             return;
         }
 
-        let mname = self.field(attr, MODULE);
-        let mangled_cgu_name = CodegenUnit::mangle_name(&mname.as_str());
-        let mangled_cgu_name = Symbol::intern(&mangled_cgu_name).as_interned_str();
+        let user_path = self.field(attr, MODULE).as_str().to_string();
+        let crate_name = self.tcx.crate_name(LOCAL_CRATE).as_str().to_string();
+
+        if !user_path.starts_with(&crate_name) {
+            let msg = format!("Found malformed codegen unit name `{}`. \
+                Codegen units names must always start with the name of the \
+                crate (`{}` in this case).", user_path, crate_name);
+            self.tcx.sess.span_fatal(attr.span, &msg);
+        }
+
+        // Split of the "special suffix" if there is one.
+        let (user_path, cgu_special_suffix) = if let Some(index) = user_path.rfind(".") {
+            (&user_path[..index], Some(&user_path[index + 1 ..]))
+        } else {
+            (&user_path[..], None)
+        };
+
+        let mut cgu_path_components = user_path.split("-").collect::<Vec<_>>();
+
+        // Remove the crate name
+        assert_eq!(cgu_path_components.remove(0), crate_name);
+
+        let cgu_name_builder = &mut CodegenUnitNameBuilder::new(self.tcx);
+        let cgu_name = cgu_name_builder.build_cgu_name(LOCAL_CRATE,
+                                                       cgu_path_components,
+                                                       cgu_special_suffix);
+
+        debug!("mapping '{}' to cgu name '{}'", self.field(attr, MODULE), cgu_name);
 
         let dep_node = DepNode::new(self.tcx,
-                                    DepConstructor::CompileCodegenUnit(mangled_cgu_name));
+                                    DepConstructor::CompileCodegenUnit(cgu_name));
 
         if let Some(loaded_from_cache) = self.tcx.dep_graph.was_loaded_from_cache(&dep_node) {
             match (disposition, loaded_from_cache) {
@@ -85,13 +110,13 @@ impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> {
                     self.tcx.sess.span_err(
                         attr.span,
                         &format!("expected module named `{}` to be Reused but is Codegened",
-                                 mname));
+                                 user_path));
                 }
                 (Disposition::Codegened, true) => {
                     self.tcx.sess.span_err(
                         attr.span,
                         &format!("expected module named `{}` to be Codegened but is Reused",
-                                 mname));
+                                 user_path));
                 }
                 (Disposition::Reused, true) |
                 (Disposition::Codegened, false) => {
@@ -99,7 +124,19 @@ impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> {
                 }
             }
         } else {
-            self.tcx.sess.span_err(attr.span, &format!("no module named `{}`", mname));
+            let available_cgus = self.tcx
+                .collect_and_partition_mono_items(LOCAL_CRATE)
+                .1
+                .iter()
+                .map(|cgu| format!("{}", cgu.name()))
+                .collect::<Vec<String>>()
+                .join(", ");
+
+            self.tcx.sess.span_err(attr.span,
+                &format!("no module named `{}` (mangled: {}).\nAvailable modules: {}",
+                    user_path,
+                    cgu_name,
+                    available_cgus));
         }
     }
 
diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs
index 4e32ca483a1..73d5d1d0948 100644
--- a/src/librustc_mir/monomorphize/partitioning.rs
+++ b/src/librustc_mir/monomorphize/partitioning.rs
@@ -105,9 +105,9 @@
 use monomorphize::collector::InliningMap;
 use rustc::dep_graph::WorkProductId;
 use rustc::hir::CodegenFnAttrFlags;
-use rustc::hir::def_id::DefId;
+use rustc::hir::def_id::{DefId, LOCAL_CRATE, CRATE_DEF_INDEX};
 use rustc::hir::map::DefPathData;
-use rustc::mir::mono::{Linkage, Visibility};
+use rustc::mir::mono::{Linkage, Visibility, CodegenUnitNameBuilder};
 use rustc::middle::exported_symbols::SymbolExportLevel;
 use rustc::ty::{self, TyCtxt, InstanceDef};
 use rustc::ty::item_path::characteristic_def_id_of_type;
@@ -115,7 +115,7 @@ use rustc::util::nodemap::{FxHashMap, FxHashSet};
 use std::collections::hash_map::Entry;
 use std::cmp;
 use syntax::ast::NodeId;
-use syntax::symbol::{Symbol, InternedString};
+use syntax::symbol::InternedString;
 use rustc::mir::mono::MonoItem;
 use monomorphize::item::{MonoItemExt, InstantiationMode};
 
@@ -203,17 +203,10 @@ impl<'tcx> CodegenUnitExt<'tcx> for CodegenUnit<'tcx> {
 }
 
 // Anything we can't find a proper codegen unit for goes into this.
-fn fallback_cgu_name(tcx: TyCtxt) -> InternedString {
-    const FALLBACK_CODEGEN_UNIT: &'static str = "__rustc_fallback_codegen_unit";
-
-    if tcx.sess.opts.debugging_opts.human_readable_cgu_names {
-        Symbol::intern(FALLBACK_CODEGEN_UNIT).as_interned_str()
-    } else {
-        Symbol::intern(&CodegenUnit::mangle_name(FALLBACK_CODEGEN_UNIT)).as_interned_str()
-    }
+fn fallback_cgu_name(name_builder: &mut CodegenUnitNameBuilder) -> InternedString {
+    name_builder.build_cgu_name(LOCAL_CRATE, &["fallback"], Some("cgu"))
 }
 
-
 pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                               mono_items: I,
                               strategy: PartitioningStrategy,
@@ -224,8 +217,7 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // In the first step, we place all regular monomorphizations into their
     // respective 'home' codegen unit. Regular monomorphizations are all
     // functions and statics defined in the local crate.
-    let mut initial_partitioning = place_root_mono_items(tcx,
-                                                                mono_items);
+    let mut initial_partitioning = place_root_mono_items(tcx, mono_items);
 
     initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(&tcx));
 
@@ -234,7 +226,7 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // If the partitioning should produce a fixed count of codegen units, merge
     // until that count is reached.
     if let PartitioningStrategy::FixedUnitCount(count) = strategy {
-        merge_codegen_units(&mut initial_partitioning, count, &tcx.crate_name.as_str());
+        merge_codegen_units(tcx, &mut initial_partitioning, count);
 
         debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter());
     }
@@ -308,6 +300,9 @@ fn place_root_mono_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let export_generics = tcx.sess.opts.share_generics() &&
                           tcx.local_crate_exports_generics();
 
+    let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
+    let cgu_name_cache = &mut FxHashMap();
+
     for mono_item in mono_items {
         match mono_item.instantiation_mode(tcx) {
             InstantiationMode::GloballyShared { .. } => {}
@@ -319,8 +314,12 @@ fn place_root_mono_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           mono_item.is_generic_fn();
 
         let codegen_unit_name = match characteristic_def_id {
-            Some(def_id) => compute_codegen_unit_name(tcx, def_id, is_volatile),
-            None => fallback_cgu_name(tcx),
+            Some(def_id) => compute_codegen_unit_name(tcx,
+                                                      cgu_name_builder,
+                                                      def_id,
+                                                      is_volatile,
+                                                      cgu_name_cache),
+            None => fallback_cgu_name(cgu_name_builder),
         };
 
         let codegen_unit = codegen_units.entry(codegen_unit_name.clone())
@@ -344,7 +343,7 @@ fn place_root_mono_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // always ensure we have at least one CGU; otherwise, if we have a
     // crate with just types (for example), we could wind up with no CGU
     if codegen_units.is_empty() {
-        let codegen_unit_name = fallback_cgu_name(tcx);
+        let codegen_unit_name = fallback_cgu_name(cgu_name_builder);
         codegen_units.insert(codegen_unit_name.clone(),
                              CodegenUnit::new(codegen_unit_name.clone()));
     }
@@ -552,9 +551,9 @@ fn default_visibility(tcx: TyCtxt, id: DefId, is_generic: bool) -> Visibility {
     }
 }
 
-fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning<'tcx>,
-                             target_cgu_count: usize,
-                             crate_name: &str) {
+fn merge_codegen_units<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>,
+                             initial_partitioning: &mut PreInliningPartitioning<'tcx>,
+                             target_cgu_count: usize) {
     assert!(target_cgu_count >= 1);
     let codegen_units = &mut initial_partitioning.codegen_units;
 
@@ -582,14 +581,15 @@ fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning<
         }
     }
 
+    let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
     for (index, cgu) in codegen_units.iter_mut().enumerate() {
-        cgu.set_name(numbered_codegen_unit_name(crate_name, index));
+        cgu.set_name(numbered_codegen_unit_name(cgu_name_builder, index));
     }
 }
 
 fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning<'tcx>,
-                                         inlining_map: &InliningMap<'tcx>)
-                                         -> PostInliningPartitioning<'tcx> {
+                                  inlining_map: &InliningMap<'tcx>)
+                                  -> PostInliningPartitioning<'tcx> {
     let mut new_partitioning = Vec::new();
     let mut mono_item_placements = FxHashMap();
 
@@ -783,46 +783,72 @@ fn characteristic_def_id_of_mono_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
-fn compute_codegen_unit_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                       def_id: DefId,
-                                       volatile: bool)
-                                       -> InternedString {
-    // Unfortunately we cannot just use the `ty::item_path` infrastructure here
-    // because we need paths to modules and the DefIds of those are not
-    // available anymore for external items.
-    let mut cgu_name = String::with_capacity(64);
-
-    let def_path = tcx.def_path(def_id);
-    cgu_name.push_str(&tcx.crate_name(def_path.krate).as_str());
-
-    for part in tcx.def_path(def_id)
-                   .data
-                   .iter()
-                   .take_while(|part| {
-                        match part.data {
-                            DefPathData::Module(..) => true,
-                            _ => false,
-                        }
-                    }) {
-        cgu_name.push_str("-");
-        cgu_name.push_str(&part.data.as_interned_str().as_str());
-    }
+type CguNameCache = FxHashMap<(DefId, bool), InternedString>;
+
+fn compute_codegen_unit_name(tcx: TyCtxt,
+                             name_builder: &mut CodegenUnitNameBuilder,
+                             def_id: DefId,
+                             volatile: bool,
+                             cache: &mut CguNameCache)
+                             -> InternedString {
+    // Find the innermost module that is not nested within a function
+    let mut current_def_id = def_id;
+    let mut cgu_def_id = None;
+    // Walk backwards from the item we want to find the module for:
+    loop {
+        let def_key = tcx.def_key(current_def_id);
+
+        match def_key.disambiguated_data.data {
+            DefPathData::Module(..) => {
+                if cgu_def_id.is_none() {
+                    cgu_def_id = Some(current_def_id);
+                }
+            }
+            DefPathData::CrateRoot { .. } => {
+                if cgu_def_id.is_none() {
+                    // If we have not found a module yet, take the crate root.
+                    cgu_def_id = Some(DefId {
+                        krate: def_id.krate,
+                        index: CRATE_DEF_INDEX,
+                    });
+                }
+                break
+            }
+            _ => {
+                // If we encounter something that is not a module, throw away
+                // any module that we've found so far because we now know that
+                // it is nested within something else.
+                cgu_def_id = None;
+            }
+        }
 
-    if volatile {
-        cgu_name.push_str(".volatile");
+        current_def_id.index = def_key.parent.unwrap();
     }
 
-    let cgu_name = if tcx.sess.opts.debugging_opts.human_readable_cgu_names {
-        cgu_name
-    } else {
-        CodegenUnit::mangle_name(&cgu_name)
-    };
+    let cgu_def_id = cgu_def_id.unwrap();
+
+    cache.entry((cgu_def_id, volatile)).or_insert_with(|| {
+        let def_path = tcx.def_path(cgu_def_id);
+
+        let components = def_path
+            .data
+            .iter()
+            .map(|part| part.data.as_interned_str());
+
+        let volatile_suffix = if volatile {
+            Some("volatile")
+        } else {
+            None
+        };
 
-    Symbol::intern(&cgu_name[..]).as_interned_str()
+        name_builder.build_cgu_name(def_path.krate, components, volatile_suffix)
+    }).clone()
 }
 
-fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString {
-    Symbol::intern(&format!("{}{}", crate_name, index)).as_interned_str()
+fn numbered_codegen_unit_name(name_builder: &mut CodegenUnitNameBuilder,
+                              index: usize)
+                              -> InternedString {
+    name_builder.build_cgu_name_no_mangle(LOCAL_CRATE, &["cgu"], Some(index))
 }
 
 fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
diff --git a/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs
index 49e4b8d43c1..cec88f1c6a2 100644
--- a/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs
+++ b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs
@@ -14,7 +14,7 @@
 
 #![feature(start)]
 
-//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<drop_in_place_intrinsic::StructWithDtor[0]> @@ drop_in_place_intrinsic0[Internal]
+//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<drop_in_place_intrinsic::StructWithDtor[0]> @@ drop_in_place_intrinsic-cgu.0[Internal]
 struct StructWithDtor(u32);
 
 impl Drop for StructWithDtor {
@@ -26,7 +26,7 @@ impl Drop for StructWithDtor {
 #[start]
 fn start(_: isize, _: *const *const u8) -> isize {
 
-    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]; 2]> @@ drop_in_place_intrinsic0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]; 2]> @@ drop_in_place_intrinsic-cgu.0[Internal]
     let x = [StructWithDtor(0), StructWithDtor(1)];
 
     drop_slice_in_place(&x);
@@ -40,7 +40,7 @@ fn drop_slice_in_place(x: &[StructWithDtor]) {
         // This is the interesting thing in this test case: Normally we would
         // not have drop-glue for the unsized [StructWithDtor]. This has to be
         // generated though when the drop_in_place() intrinsic is used.
-        //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]]> @@ drop_in_place_intrinsic0[Internal]
+        //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]]> @@ drop_in_place_intrinsic-cgu.0[Internal]
         ::std::ptr::drop_in_place(x as *const _ as *mut [StructWithDtor]);
     }
 }
diff --git a/src/test/codegen-units/item-collection/generic-drop-glue.rs b/src/test/codegen-units/item-collection/generic-drop-glue.rs
index aad32d1eb7c..5afa519bc59 100644
--- a/src/test/codegen-units/item-collection/generic-drop-glue.rs
+++ b/src/test/codegen-units/item-collection/generic-drop-glue.rs
@@ -47,7 +47,7 @@ enum EnumNoDrop<T1, T2> {
 struct NonGenericNoDrop(i32);
 
 struct NonGenericWithDrop(i32);
-//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::NonGenericWithDrop[0]> @@ generic_drop_glue0[Internal]
+//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::NonGenericWithDrop[0]> @@ generic_drop_glue-cgu.0[Internal]
 
 impl Drop for NonGenericWithDrop {
     //~ MONO_ITEM fn generic_drop_glue::{{impl}}[2]::drop[0]
@@ -57,11 +57,11 @@ impl Drop for NonGenericWithDrop {
 //~ MONO_ITEM fn generic_drop_glue::start[0]
 #[start]
 fn start(_: isize, _: *const *const u8) -> isize {
-    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::StructWithDrop[0]<i8, char>> @@ generic_drop_glue0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::StructWithDrop[0]<i8, char>> @@ generic_drop_glue-cgu.0[Internal]
     //~ MONO_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0]<i8, char>
     let _ = StructWithDrop { x: 0i8, y: 'a' }.x;
 
-    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::StructWithDrop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]>> @@ generic_drop_glue0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::StructWithDrop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]>> @@ generic_drop_glue-cgu.0[Internal]
     //~ MONO_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]>
     let _ = StructWithDrop { x: "&str", y: NonGenericNoDrop(0) }.y;
 
@@ -70,17 +70,17 @@ fn start(_: isize, _: *const *const u8) -> isize {
 
     // This is supposed to generate drop-glue because it contains a field that
     // needs to be dropped.
-    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::StructNoDrop[0]<generic_drop_glue::NonGenericWithDrop[0], f64>> @@ generic_drop_glue0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::StructNoDrop[0]<generic_drop_glue::NonGenericWithDrop[0], f64>> @@ generic_drop_glue-cgu.0[Internal]
     let _ = StructNoDrop { x: NonGenericWithDrop(0), y: 0f64 }.y;
 
-    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::EnumWithDrop[0]<i32, i64>> @@ generic_drop_glue0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::EnumWithDrop[0]<i32, i64>> @@ generic_drop_glue-cgu.0[Internal]
     //~ MONO_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0]<i32, i64>
     let _ = match EnumWithDrop::A::<i32, i64>(0) {
         EnumWithDrop::A(x) => x,
         EnumWithDrop::B(x) => x as i32
     };
 
-    //~MONO_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::EnumWithDrop[0]<f64, f32>> @@ generic_drop_glue0[Internal]
+    //~MONO_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::EnumWithDrop[0]<f64, f32>> @@ generic_drop_glue-cgu.0[Internal]
     //~ MONO_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0]<f64, f32>
     let _ = match EnumWithDrop::B::<f64, f32>(1.0) {
         EnumWithDrop::A(x) => x,
diff --git a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs
index 5c6201da252..d09d343a845 100644
--- a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs
+++ b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs
@@ -34,13 +34,13 @@ impl<T> Trait for Struct<T> {
 fn start(_: isize, _: *const *const u8) -> isize {
     let s1 = Struct { _a: 0u32 };
 
-    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<instantiation_through_vtable::Struct[0]<u32>> @@ instantiation_through_vtable0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<instantiation_through_vtable::Struct[0]<u32>> @@ instantiation_through_vtable-cgu.0[Internal]
     //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0]<u32>
     //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0]<u32>
     let _ = &s1 as &Trait;
 
     let s1 = Struct { _a: 0u64 };
-    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<instantiation_through_vtable::Struct[0]<u64>> @@ instantiation_through_vtable0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<instantiation_through_vtable::Struct[0]<u64>> @@ instantiation_through_vtable-cgu.0[Internal]
     //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0]<u64>
     //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0]<u64>
     let _ = &s1 as &Trait;
diff --git a/src/test/codegen-units/item-collection/non-generic-drop-glue.rs b/src/test/codegen-units/item-collection/non-generic-drop-glue.rs
index 6ca24aa5b4b..a939dd56cda 100644
--- a/src/test/codegen-units/item-collection/non-generic-drop-glue.rs
+++ b/src/test/codegen-units/item-collection/non-generic-drop-glue.rs
@@ -15,7 +15,7 @@
 #![deny(dead_code)]
 #![feature(start)]
 
-//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<non_generic_drop_glue::StructWithDrop[0]> @@ non_generic_drop_glue0[Internal]
+//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<non_generic_drop_glue::StructWithDrop[0]> @@ non_generic_drop_glue-cgu.0[Internal]
 struct StructWithDrop {
     x: i32
 }
@@ -29,7 +29,7 @@ struct StructNoDrop {
     x: i32
 }
 
-//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<non_generic_drop_glue::EnumWithDrop[0]> @@ non_generic_drop_glue0[Internal]
+//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<non_generic_drop_glue::EnumWithDrop[0]> @@ non_generic_drop_glue-cgu.0[Internal]
 enum EnumWithDrop {
     A(i32)
 }
diff --git a/src/test/codegen-units/item-collection/transitive-drop-glue.rs b/src/test/codegen-units/item-collection/transitive-drop-glue.rs
index d20213c109b..7bbc9b6d0fb 100644
--- a/src/test/codegen-units/item-collection/transitive-drop-glue.rs
+++ b/src/test/codegen-units/item-collection/transitive-drop-glue.rs
@@ -15,11 +15,11 @@
 #![deny(dead_code)]
 #![feature(start)]
 
-//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::Root[0]> @@ transitive_drop_glue0[Internal]
+//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::Root[0]> @@ transitive_drop_glue-cgu.0[Internal]
 struct Root(Intermediate);
-//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::Intermediate[0]> @@ transitive_drop_glue0[Internal]
+//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::Intermediate[0]> @@ transitive_drop_glue-cgu.0[Internal]
 struct Intermediate(Leaf);
-//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::Leaf[0]> @@ transitive_drop_glue0[Internal]
+//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::Leaf[0]> @@ transitive_drop_glue-cgu.0[Internal]
 struct Leaf;
 
 impl Drop for Leaf {
@@ -40,15 +40,15 @@ impl<T> Drop for LeafGen<T> {
 fn start(_: isize, _: *const *const u8) -> isize {
     let _ = Root(Intermediate(Leaf));
 
-    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::RootGen[0]<u32>> @@ transitive_drop_glue0[Internal]
-    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::IntermediateGen[0]<u32>> @@ transitive_drop_glue0[Internal]
-    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::LeafGen[0]<u32>> @@ transitive_drop_glue0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::RootGen[0]<u32>> @@ transitive_drop_glue-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::IntermediateGen[0]<u32>> @@ transitive_drop_glue-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::LeafGen[0]<u32>> @@ transitive_drop_glue-cgu.0[Internal]
     //~ MONO_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0]<u32>
     let _ = RootGen(IntermediateGen(LeafGen(0u32)));
 
-    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::RootGen[0]<i16>> @@ transitive_drop_glue0[Internal]
-    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::IntermediateGen[0]<i16>> @@ transitive_drop_glue0[Internal]
-    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::LeafGen[0]<i16>> @@ transitive_drop_glue0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::RootGen[0]<i16>> @@ transitive_drop_glue-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::IntermediateGen[0]<i16>> @@ transitive_drop_glue-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::LeafGen[0]<i16>> @@ transitive_drop_glue-cgu.0[Internal]
     //~ MONO_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0]<i16>
     let _ = RootGen(IntermediateGen(LeafGen(0i16)));
 
diff --git a/src/test/codegen-units/item-collection/tuple-drop-glue.rs b/src/test/codegen-units/item-collection/tuple-drop-glue.rs
index 9e4cc6ea6f0..865570ccfa5 100644
--- a/src/test/codegen-units/item-collection/tuple-drop-glue.rs
+++ b/src/test/codegen-units/item-collection/tuple-drop-glue.rs
@@ -15,7 +15,7 @@
 #![deny(dead_code)]
 #![feature(start)]
 
-//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<tuple_drop_glue::Dropped[0]> @@ tuple_drop_glue0[Internal]
+//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<tuple_drop_glue::Dropped[0]> @@ tuple_drop_glue-cgu.0[Internal]
 struct Dropped;
 
 impl Drop for Dropped {
@@ -26,11 +26,11 @@ impl Drop for Dropped {
 //~ MONO_ITEM fn tuple_drop_glue::start[0]
 #[start]
 fn start(_: isize, _: *const *const u8) -> isize {
-    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(u32, tuple_drop_glue::Dropped[0])> @@ tuple_drop_glue0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(u32, tuple_drop_glue::Dropped[0])> @@ tuple_drop_glue-cgu.0[Internal]
     let x = (0u32, Dropped);
 
-    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(i16, (tuple_drop_glue::Dropped[0], bool))> @@ tuple_drop_glue0[Internal]
-    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(tuple_drop_glue::Dropped[0], bool)> @@ tuple_drop_glue0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(i16, (tuple_drop_glue::Dropped[0], bool))> @@ tuple_drop_glue-cgu.0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(tuple_drop_glue::Dropped[0], bool)> @@ tuple_drop_glue-cgu.0[Internal]
     let x = (0i16, (Dropped, true));
 
     0
diff --git a/src/test/codegen-units/item-collection/unsizing.rs b/src/test/codegen-units/item-collection/unsizing.rs
index adc0eb6c709..5e9a3258c7a 100644
--- a/src/test/codegen-units/item-collection/unsizing.rs
+++ b/src/test/codegen-units/item-collection/unsizing.rs
@@ -59,13 +59,13 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Wrapper<U>> for Wrapper<T>
 fn start(_: isize, _: *const *const u8) -> isize {
     // simple case
     let bool_sized = &true;
-    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<bool> @@ unsizing0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<bool> @@ unsizing-cgu.0[Internal]
     //~ MONO_ITEM fn unsizing::{{impl}}[0]::foo[0]
     let _bool_unsized = bool_sized as &Trait;
 
     let char_sized = &'a';
 
-    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<char> @@ unsizing0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<char> @@ unsizing-cgu.0[Internal]
     //~ MONO_ITEM fn unsizing::{{impl}}[1]::foo[0]
     let _char_unsized = char_sized as &Trait;
 
@@ -75,13 +75,13 @@ fn start(_: isize, _: *const *const u8) -> isize {
         _b: 2,
         _c: 3.0f64
     };
-    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<f64> @@ unsizing0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<f64> @@ unsizing-cgu.0[Internal]
     //~ MONO_ITEM fn unsizing::{{impl}}[2]::foo[0]
     let _struct_unsized = struct_sized as &Struct<Trait>;
 
     // custom coercion
     let wrapper_sized = Wrapper(&0u32);
-    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<u32> @@ unsizing0[Internal]
+    //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<u32> @@ unsizing-cgu.0[Internal]
     //~ MONO_ITEM fn unsizing::{{impl}}[3]::foo[0]
     let _wrapper_sized = wrapper_sized as Wrapper<Trait>;
 
diff --git a/src/test/incremental/issue-39828/auxiliary/generic.rs b/src/test/incremental/issue-39828/auxiliary/generic.rs
index a562eab1768..5491827af8a 100644
--- a/src/test/incremental/issue-39828/auxiliary/generic.rs
+++ b/src/test/incremental/issue-39828/auxiliary/generic.rs
@@ -11,7 +11,7 @@
 // revisions:rpass1 rpass2
 // compile-flags: -Z query-dep-graph
 
-#![rustc_partition_reused(module="__rustc_fallback_codegen_unit", cfg="rpass2")]
+#![rustc_partition_reused(module="generic-fallback.cgu", cfg="rpass2")]
 #![feature(rustc_attrs)]
 
 #![crate_type="rlib"]
diff --git a/src/test/run-make-fulldeps/cross-lang-lto/Makefile b/src/test/run-make-fulldeps/cross-lang-lto/Makefile
index 6d06fade352..1d072e03de3 100644
--- a/src/test/run-make-fulldeps/cross-lang-lto/Makefile
+++ b/src/test/run-make-fulldeps/cross-lang-lto/Makefile
@@ -16,22 +16,22 @@ all: staticlib staticlib-fat-lto staticlib-thin-lto rlib exe cdylib rdylib
 staticlib: lib.rs
 	$(BUILD_LIB) --crate-type=staticlib -o $(TMPDIR)/liblib.a
 	$(call EXTRACT_OBJS, liblib.a)
-	$(ASSERT_IS_BITCODE_OBJ) $(TMPDIR)/liblib.lib0.rcgu.o
+	for file in $(TMPDIR)/liblib.*.rcgu.o; do $(ASSERT_IS_BITCODE_OBJ) $$file; done
 
 staticlib-fat-lto: lib.rs
 	$(BUILD_LIB) --crate-type=staticlib -o $(TMPDIR)/liblib-fat-lto.a -Clto=fat
 	$(call EXTRACT_OBJS, liblib-fat-lto.a)
-	$(ASSERT_IS_BITCODE_OBJ) $(TMPDIR)/liblib-fat-lto.lib0.rcgu.o
+	for file in $(TMPDIR)/liblib-fat-lto.*.rcgu.o; do $(ASSERT_IS_BITCODE_OBJ) $$file; done
 
 staticlib-thin-lto: lib.rs
 	$(BUILD_LIB) --crate-type=staticlib -o $(TMPDIR)/liblib-thin-lto.a -Clto=thin
 	$(call EXTRACT_OBJS, liblib-thin-lto.a)
-	$(ASSERT_IS_BITCODE_OBJ) $(TMPDIR)/liblib-thin-lto.lib0.rcgu.o
+	for file in $(TMPDIR)/liblib-thin-lto.*.rcgu.o; do $(ASSERT_IS_BITCODE_OBJ) $$file; done
 
 rlib: lib.rs
 	$(BUILD_LIB) --crate-type=rlib -o $(TMPDIR)/liblib.rlib
 	$(call EXTRACT_OBJS, liblib.rlib)
-	$(ASSERT_IS_BITCODE_OBJ) $(TMPDIR)/liblib.lib0.rcgu.o
+	for file in $(TMPDIR)/liblib.*.rcgu.o; do $(ASSERT_IS_BITCODE_OBJ) $$file; done
 
 cdylib: lib.rs
 	$(BUILD_LIB) --crate-type=cdylib --emit=obj -o $(TMPDIR)/cdylib.o
diff --git a/src/test/run-make-fulldeps/extra-filename-with-temp-outputs/Makefile b/src/test/run-make-fulldeps/extra-filename-with-temp-outputs/Makefile
index 6de4f97df0c..e46390a9d0c 100644
--- a/src/test/run-make-fulldeps/extra-filename-with-temp-outputs/Makefile
+++ b/src/test/run-make-fulldeps/extra-filename-with-temp-outputs/Makefile
@@ -2,5 +2,5 @@
 
 all:
 	$(RUSTC) -C extra-filename=bar foo.rs -C save-temps
-	rm $(TMPDIR)/foobar.foo0.rcgu.o
+	rm $(TMPDIR)/foobar.foo*0.rcgu.o
 	rm $(TMPDIR)/$(call BIN,foobar)
diff --git a/src/test/ui/lto-duplicate-symbols.stderr b/src/test/ui/lto-duplicate-symbols.stderr
index 2f0e57199bb..5760cb9a8fd 100644
--- a/src/test/ui/lto-duplicate-symbols.stderr
+++ b/src/test/ui/lto-duplicate-symbols.stderr
@@ -1,6 +1,6 @@
 warning: Linking globals named 'foo': symbol multiply defined!
 
-error: failed to load bc of "lto_duplicate_symbols10-8787f43e282added376259c1adb08b80.rs": 
+error: failed to load bc of "lto_duplicate_symbols1.3a1fbbbh-cgu.0": 
 
 error: aborting due to previous error
 
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 4b246ab6745..b1361730826 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -2209,12 +2209,12 @@ impl<'test> TestCx<'test> {
             .stdout
             .lines()
             .filter(|line| line.starts_with(PREFIX))
-            .map(str_to_mono_item)
+            .map(|line| str_to_mono_item(line, true))
             .collect();
 
         let expected: Vec<MonoItem> = errors::load_errors(&self.testpaths.file, None)
             .iter()
-            .map(|e| str_to_mono_item(&e.msg[..]))
+            .map(|e| str_to_mono_item(&e.msg[..], false))
             .collect();
 
         let mut missing = Vec::new();
@@ -2299,14 +2299,14 @@ impl<'test> TestCx<'test> {
         }
 
         // [MONO_ITEM] name [@@ (cgu)+]
-        fn str_to_mono_item(s: &str) -> MonoItem {
+        fn str_to_mono_item(s: &str, cgu_has_crate_disambiguator: bool) -> MonoItem {
             let s = if s.starts_with(PREFIX) {
                 (&s[PREFIX.len()..]).trim()
             } else {
                 s.trim()
             };
 
-            let full_string = format!("{}{}", PREFIX, s.trim().to_owned());
+            let full_string = format!("{}{}", PREFIX, s);
 
             let parts: Vec<&str> = s
                 .split(CGU_MARKER)
@@ -2323,7 +2323,13 @@ impl<'test> TestCx<'test> {
                     .split(' ')
                     .map(str::trim)
                     .filter(|s| !s.is_empty())
-                    .map(str::to_owned)
+                    .map(|s| {
+                        if cgu_has_crate_disambiguator {
+                            remove_crate_disambiguator_from_cgu(s)
+                        } else {
+                            s.to_string()
+                        }
+                    })
                     .collect()
             } else {
                 HashSet::new()
@@ -2348,6 +2354,23 @@ impl<'test> TestCx<'test> {
 
             string
         }
+
+        fn remove_crate_disambiguator_from_cgu(cgu: &str) -> String {
+            // The first '.' is the start of the crate disambiguator
+            let disambiguator_start = cgu.find('.')
+                .expect("Could not find start of crate disambiguator in CGU spec");
+
+            // The first non-alphanumeric character is the end of the disambiguator
+            let disambiguator_end = cgu[disambiguator_start + 1 ..]
+                .find(|c| !char::is_alphanumeric(c))
+                .expect("Could not find end of crate disambiguator in CGU spec")
+                + disambiguator_start + 1;
+
+            let mut result = cgu[0 .. disambiguator_start].to_string();
+            result.push_str(&cgu[disambiguator_end ..]);
+
+            result
+        }
     }
 
     fn init_incremental_test(&self) {