about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-09-09 22:17:42 +0000
committerbors <bors@rust-lang.org>2020-09-09 22:17:42 +0000
commit97eb606e4b2becd17d46a67d87169f52b210e67c (patch)
tree7a8f83e2ca64a5f2225f4476ef4a61de8e4e8a2d /compiler
parente2be5f568d1f60365b825530f5b5cb722460591b (diff)
parent32714eb6bc3cbfe48774e85472ad8431fba3c7c8 (diff)
downloadrust-97eb606e4b2becd17d46a67d87169f52b210e67c.tar.gz
rust-97eb606e4b2becd17d46a67d87169f52b210e67c.zip
Auto merge of #76540 - tmandry:rollup-5ogt8x0, r=tmandry
Rollup of 14 pull requests

Successful merges:

 - #75094 (Add `-Z combine_cgu` flag)
 - #75984 (Improve unresolved use error message)
 - #76141 (Address review comments about config.toml from rustc-dev-guide PR)
 - #76313 (Improved the MIR spanview output)
 - #76430 (Add align to rustc-attrs unstable book)
 - #76465 (Add a script to automatically update Rust/Clang versions in documentation)
 - #76473 (Add missed spaces to GCC-WARNING.txt)
 - #76481 (Convert repetitive target_pointer_width checks to const solution.)
 - #76493 (Remove a stray ignore-tidy-undocumented-unsafe)
 - #76504 (Capitalize safety comments)
 - #76515 (SessionDiagnostic: Fix non-determinism in generated format string.)
 - #76516 (Enable GitHub Releases synchronization)
 - #76522 (remove redundant clones)
 - #76523 (Remove unused PlaceContext::NonUse(NonUseContext::Coverage))

Failed merges:

r? `@ghost`
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs25
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs59
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/write.rs6
-rw-r--r--compiler/rustc_data_structures/src/temp_dir.rs2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0433.md16
-rw-r--r--compiler/rustc_macros/src/session_diagnostic.rs11
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs2
-rw-r--r--compiler/rustc_mir/src/borrow_check/def_use.rs3
-rw-r--r--compiler/rustc_mir/src/dataflow/impls/init_locals.rs1
-rw-r--r--compiler/rustc_mir/src/transform/instrument_coverage.rs2
-rw-r--r--compiler/rustc_mir/src/util/spanview.rs379
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs2
-rw-r--r--compiler/rustc_resolve/src/lib.rs9
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs2
17 files changed, 417 insertions, 117 deletions
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index 7c710a1cb3d..4b2d5907a02 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -346,14 +346,14 @@ fn fat_lto(
     Ok(LtoModuleCodegen::Fat { module: Some(module), _serialized_bitcode: serialized_bitcode })
 }
 
-struct Linker<'a>(&'a mut llvm::Linker<'a>);
+crate struct Linker<'a>(&'a mut llvm::Linker<'a>);
 
 impl Linker<'a> {
-    fn new(llmod: &'a llvm::Module) -> Self {
+    crate fn new(llmod: &'a llvm::Module) -> Self {
         unsafe { Linker(llvm::LLVMRustLinkerNew(llmod)) }
     }
 
-    fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> {
+    crate fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> {
         unsafe {
             if llvm::LLVMRustLinkerAdd(
                 self.0,
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 6f386c1287c..937821e9d4f 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -617,6 +617,31 @@ unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static
     }
 }
 
+pub(crate) fn link(
+    cgcx: &CodegenContext<LlvmCodegenBackend>,
+    diag_handler: &Handler,
+    mut modules: Vec<ModuleCodegen<ModuleLlvm>>,
+) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> {
+    use super::lto::{Linker, ModuleBuffer};
+    // Sort the modules by name to ensure to ensure deterministic behavior.
+    modules.sort_by(|a, b| a.name.cmp(&b.name));
+    let (first, elements) =
+        modules.split_first().expect("Bug! modules must contain at least one module.");
+
+    let mut linker = Linker::new(first.module_llvm.llmod());
+    for module in elements {
+        let _timer =
+            cgcx.prof.generic_activity_with_arg("LLVM_link_module", format!("{:?}", module.name));
+        let buffer = ModuleBuffer::new(module.module_llvm.llmod());
+        linker.add(&buffer.data()).map_err(|()| {
+            let msg = format!("failed to serialize module {:?}", module.name);
+            llvm_err(&diag_handler, &msg)
+        })?;
+    }
+    drop(linker);
+    Ok(modules.remove(0))
+}
+
 pub(crate) unsafe fn codegen(
     cgcx: &CodegenContext<LlvmCodegenBackend>,
     diag_handler: &Handler,
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 67d4b2642c0..2e2abe9fb30 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -130,6 +130,13 @@ impl WriteBackendMethods for LlvmCodegenBackend {
             llvm::LLVMRustPrintPassTimings();
         }
     }
+    fn run_link(
+        cgcx: &CodegenContext<Self>,
+        diag_handler: &Handler,
+        modules: Vec<ModuleCodegen<Self::Module>>,
+    ) -> Result<ModuleCodegen<Self::Module>, FatalError> {
+        back::write::link(cgcx, diag_handler, modules)
+    }
     fn run_fat_lto(
         cgcx: &CodegenContext<Self>,
         modules: Vec<FatLTOInput<Self>>,
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 7d69bb983dd..0edf0fcd1a2 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -702,6 +702,7 @@ impl<B: WriteBackendMethods> WorkItem<B> {
 
 enum WorkItemResult<B: WriteBackendMethods> {
     Compiled(CompiledModule),
+    NeedsLink(ModuleCodegen<B::Module>),
     NeedsFatLTO(FatLTOInput<B>),
     NeedsThinLTO(String, B::ThinBuffer),
 }
@@ -801,11 +802,8 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>(
         None
     };
 
-    Ok(match lto_type {
-        ComputedLtoType::No => {
-            let module = unsafe { B::codegen(cgcx, &diag_handler, module, module_config)? };
-            WorkItemResult::Compiled(module)
-        }
+    match lto_type {
+        ComputedLtoType::No => finish_intra_module_work(cgcx, module, module_config),
         ComputedLtoType::Thin => {
             let (name, thin_buffer) = B::prepare_thin(module);
             if let Some(path) = bitcode {
@@ -813,7 +811,7 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>(
                     panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e);
                 });
             }
-            WorkItemResult::NeedsThinLTO(name, thin_buffer)
+            Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer))
         }
         ComputedLtoType::Fat => match bitcode {
             Some(path) => {
@@ -821,11 +819,11 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>(
                 fs::write(&path, buffer.data()).unwrap_or_else(|e| {
                     panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e);
                 });
-                WorkItemResult::NeedsFatLTO(FatLTOInput::Serialized { name, buffer })
+                Ok(WorkItemResult::NeedsFatLTO(FatLTOInput::Serialized { name, buffer }))
             }
-            None => WorkItemResult::NeedsFatLTO(FatLTOInput::InMemory(module)),
+            None => Ok(WorkItemResult::NeedsFatLTO(FatLTOInput::InMemory(module))),
         },
-    })
+    }
 }
 
 fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
@@ -871,12 +869,25 @@ fn execute_lto_work_item<B: ExtraBackendMethods>(
     mut module: lto::LtoModuleCodegen<B>,
     module_config: &ModuleConfig,
 ) -> Result<WorkItemResult<B>, FatalError> {
+    let module = unsafe { module.optimize(cgcx)? };
+    finish_intra_module_work(cgcx, module, module_config)
+}
+
+fn finish_intra_module_work<B: ExtraBackendMethods>(
+    cgcx: &CodegenContext<B>,
+    module: ModuleCodegen<B::Module>,
+    module_config: &ModuleConfig,
+) -> Result<WorkItemResult<B>, FatalError> {
     let diag_handler = cgcx.create_diag_handler();
 
-    unsafe {
-        let module = module.optimize(cgcx)?;
-        let module = B::codegen(cgcx, &diag_handler, module, module_config)?;
+    if !cgcx.opts.debugging_opts.combine_cgu
+        || module.kind == ModuleKind::Metadata
+        || module.kind == ModuleKind::Allocator
+    {
+        let module = unsafe { B::codegen(cgcx, &diag_handler, module, module_config)? };
         Ok(WorkItemResult::Compiled(module))
+    } else {
+        Ok(WorkItemResult::NeedsLink(module))
     }
 }
 
@@ -891,6 +902,10 @@ pub enum Message<B: WriteBackendMethods> {
         thin_buffer: B::ThinBuffer,
         worker_id: usize,
     },
+    NeedsLink {
+        module: ModuleCodegen<B::Module>,
+        worker_id: usize,
+    },
     Done {
         result: Result<CompiledModule, Option<WorkerFatalError>>,
         worker_id: usize,
@@ -1178,6 +1193,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
         let mut compiled_modules = vec![];
         let mut compiled_metadata_module = None;
         let mut compiled_allocator_module = None;
+        let mut needs_link = Vec::new();
         let mut needs_fat_lto = Vec::new();
         let mut needs_thin_lto = Vec::new();
         let mut lto_import_only_modules = Vec::new();
@@ -1434,6 +1450,10 @@ fn start_executing_work<B: ExtraBackendMethods>(
                         }
                     }
                 }
+                Message::NeedsLink { module, worker_id } => {
+                    free_worker(worker_id);
+                    needs_link.push(module);
+                }
                 Message::NeedsFatLTO { result, worker_id } => {
                     assert!(!started_lto);
                     free_worker(worker_id);
@@ -1462,6 +1482,18 @@ fn start_executing_work<B: ExtraBackendMethods>(
             }
         }
 
+        let needs_link = mem::take(&mut needs_link);
+        if !needs_link.is_empty() {
+            assert!(compiled_modules.is_empty());
+            let diag_handler = cgcx.create_diag_handler();
+            let module = B::run_link(&cgcx, &diag_handler, needs_link).map_err(|_| ())?;
+            let module = unsafe {
+                B::codegen(&cgcx, &diag_handler, module, cgcx.config(ModuleKind::Regular))
+                    .map_err(|_| ())?
+            };
+            compiled_modules.push(module);
+        }
+
         // Drop to print timings
         drop(llvm_start_time);
 
@@ -1521,6 +1553,9 @@ fn spawn_work<B: ExtraBackendMethods>(cgcx: CodegenContext<B>, work: WorkItem<B>
                     Some(Ok(WorkItemResult::Compiled(m))) => {
                         Message::Done::<B> { result: Ok(m), worker_id }
                     }
+                    Some(Ok(WorkItemResult::NeedsLink(m))) => {
+                        Message::NeedsLink::<B> { module: m, worker_id }
+                    }
                     Some(Ok(WorkItemResult::NeedsFatLTO(m))) => {
                         Message::NeedsFatLTO::<B> { result: m, worker_id }
                     }
diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs
index 27d52e9b9c5..264e7c2aa92 100644
--- a/compiler/rustc_codegen_ssa/src/traits/write.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/write.rs
@@ -13,6 +13,12 @@ pub trait WriteBackendMethods: 'static + Sized + Clone {
     type ThinData: Send + Sync;
     type ThinBuffer: ThinBufferMethods;
 
+    /// Merge all modules into main_module and returning it
+    fn run_link(
+        cgcx: &CodegenContext<Self>,
+        diag_handler: &Handler,
+        modules: Vec<ModuleCodegen<Self::Module>>,
+    ) -> Result<ModuleCodegen<Self::Module>, FatalError>;
     /// Performs fat LTO by merging all modules into a single one and returning it
     /// for further optimization.
     fn run_fat_lto(
diff --git a/compiler/rustc_data_structures/src/temp_dir.rs b/compiler/rustc_data_structures/src/temp_dir.rs
index 0d9b3e3ca25..a780d2386a6 100644
--- a/compiler/rustc_data_structures/src/temp_dir.rs
+++ b/compiler/rustc_data_structures/src/temp_dir.rs
@@ -12,7 +12,7 @@ pub struct MaybeTempDir {
 
 impl Drop for MaybeTempDir {
     fn drop(&mut self) {
-        // Safety: We are in the destructor, and no further access will
+        // SAFETY: We are in the destructor, and no further access will
         // occur.
         let dir = unsafe { ManuallyDrop::take(&mut self.dir) };
         if self.keep {
diff --git a/compiler/rustc_error_codes/src/error_codes/E0433.md b/compiler/rustc_error_codes/src/error_codes/E0433.md
index f9e333e8ccd..5a64c13c9af 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0433.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0433.md
@@ -1,17 +1,27 @@
-An undeclared type or module was used.
+An undeclared crate, module, or type was used.
 
 Erroneous code example:
 
 ```compile_fail,E0433
 let map = HashMap::new();
-// error: failed to resolve: use of undeclared type or module `HashMap`
+// error: failed to resolve: use of undeclared type `HashMap`
 ```
 
 Please verify you didn't misspell the type/module's name or that you didn't
 forget to import it:
 
-
 ```
 use std::collections::HashMap; // HashMap has been imported.
 let map: HashMap<u32, u32> = HashMap::new(); // So it can be used!
 ```
+
+If you've expected to use a crate name:
+
+```compile_fail
+use ferris_wheel::BigO;
+// error: failed to resolve: use of undeclared crate or module `ferris_wheel`
+```
+
+Make sure the crate has been added as a dependency in `Cargo.toml`.
+
+To use a module from your current crate, add the `crate::` prefix to the path.
diff --git a/compiler/rustc_macros/src/session_diagnostic.rs b/compiler/rustc_macros/src/session_diagnostic.rs
index 396de77d5ee..610b9155cfc 100644
--- a/compiler/rustc_macros/src/session_diagnostic.rs
+++ b/compiler/rustc_macros/src/session_diagnostic.rs
@@ -1,11 +1,9 @@
 #![deny(unused_must_use)]
-use quote::format_ident;
-use quote::quote;
-
 use proc_macro::Diagnostic;
+use quote::{format_ident, quote};
 use syn::spanned::Spanned;
 
-use std::collections::{HashMap, HashSet};
+use std::collections::{BTreeSet, HashMap};
 
 /// Implements #[derive(SessionDiagnostic)], which allows for errors to be specified as a struct, independent
 /// from the actual diagnostics emitting code.
@@ -577,7 +575,10 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> {
     /// ```
     /// This function builds the entire call to format!.
     fn build_format(&self, input: &String, span: proc_macro2::Span) -> proc_macro2::TokenStream {
-        let mut referenced_fields: HashSet<String> = HashSet::new();
+        // This set is used later to generate the final format string. To keep builds reproducible,
+        // the iteration order needs to be deterministic, hence why we use a BTreeSet here instead
+        // of a HashSet.
+        let mut referenced_fields: BTreeSet<String> = BTreeSet::new();
 
         // At this point, we can start parsing the format string.
         let mut it = input.chars().peekable();
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 6515ae31b46..a008bd5f75f 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -1150,8 +1150,6 @@ pub enum NonUseContext {
     StorageDead,
     /// User type annotation assertions for NLL.
     AscribeUserTy,
-    /// Coverage code region and counter metadata.
-    Coverage,
     /// The data of an user variable, for debug info.
     VarDebugInfo,
 }
diff --git a/compiler/rustc_mir/src/borrow_check/def_use.rs b/compiler/rustc_mir/src/borrow_check/def_use.rs
index 6574e584406..689ec249a2f 100644
--- a/compiler/rustc_mir/src/borrow_check/def_use.rs
+++ b/compiler/rustc_mir/src/borrow_check/def_use.rs
@@ -72,8 +72,7 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
         PlaceContext::MutatingUse(MutatingUseContext::Drop) =>
             Some(DefUse::Drop),
 
-        // Coverage and debug info are neither def nor use.
-        PlaceContext::NonUse(NonUseContext::Coverage) |
+        // Debug info is neither def nor use.
         PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None,
     }
 }
diff --git a/compiler/rustc_mir/src/dataflow/impls/init_locals.rs b/compiler/rustc_mir/src/dataflow/impls/init_locals.rs
index 5da302cd1fd..bb7292cd033 100644
--- a/compiler/rustc_mir/src/dataflow/impls/init_locals.rs
+++ b/compiler/rustc_mir/src/dataflow/impls/init_locals.rs
@@ -97,7 +97,6 @@ where
             PlaceContext::NonUse(
                 NonUseContext::StorageLive
                 | NonUseContext::AscribeUserTy
-                | NonUseContext::Coverage
                 | NonUseContext::VarDebugInfo,
             )
             | PlaceContext::NonMutatingUse(
diff --git a/compiler/rustc_mir/src/transform/instrument_coverage.rs b/compiler/rustc_mir/src/transform/instrument_coverage.rs
index d3a2bd24123..8f43df8a6cb 100644
--- a/compiler/rustc_mir/src/transform/instrument_coverage.rs
+++ b/compiler/rustc_mir/src/transform/instrument_coverage.rs
@@ -309,7 +309,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
         for coverage_region in coverage_regions {
             span_viewables.push(SpanViewable {
                 span: coverage_region.span,
-                title: format!("{}", coverage_region.blocks[0].index()),
+                id: format!("{}", coverage_region.blocks[0].index()),
                 tooltip: self.make_tooltip_text(coverage_region),
             });
         }
diff --git a/compiler/rustc_mir/src/util/spanview.rs b/compiler/rustc_mir/src/util/spanview.rs
index b2f2b5fc1e6..fe33fffe0ea 100644
--- a/compiler/rustc_mir/src/util/spanview.rs
+++ b/compiler/rustc_mir/src/util/spanview.rs
@@ -3,13 +3,16 @@ use rustc_middle::hir;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::MirSpanview;
-use rustc_span::{BytePos, Pos, Span};
+use rustc_span::{BytePos, Pos, Span, SyntaxContext};
 
+use std::cmp;
 use std::io::{self, Write};
-use std::iter::Peekable;
 
 pub const TOOLTIP_INDENT: &str = "    ";
 
+const CARET: char = '\u{2038}'; // Unicode `CARET`
+const ANNOTATION_LEFT_BRACKET: char = '\u{298a}'; // Unicode `Z NOTATION RIGHT BINDING BRACKET
+const ANNOTATION_RIGHT_BRACKET: char = '\u{2989}'; // Unicode `Z NOTATION LEFT BINDING BRACKET`
 const NEW_LINE_SPAN: &str = "</span>\n<span class=\"line\">";
 const HEADER: &str = r#"<!DOCTYPE html>
 <html>
@@ -80,7 +83,7 @@ const FOOTER: &str = r#"
 /// Metadata to highlight the span of a MIR BasicBlock, Statement, or Terminator.
 pub struct SpanViewable {
     pub span: Span,
-    pub title: String,
+    pub id: String,
     pub tooltip: String,
 }
 
@@ -139,16 +142,22 @@ where
     W: Write,
 {
     let fn_span = fn_span(tcx, def_id);
-    writeln!(w, "{}", HEADER)?;
-    let mut next_pos = fn_span.lo();
+    let mut from_pos = fn_span.lo();
     let end_pos = fn_span.hi();
     let source_map = tcx.sess.source_map();
-    let start = source_map.lookup_char_pos(next_pos);
+    let start = source_map.lookup_char_pos(from_pos);
+    let indent_to_initial_start_col = " ".repeat(start.col.to_usize());
+    debug!(
+        "fn_span source is:\n{}{}",
+        indent_to_initial_start_col,
+        source_map.span_to_snippet(fn_span).expect("function should have printable source")
+    );
+    writeln!(w, "{}", HEADER)?;
     write!(
         w,
         r#"<div class="code" style="counter-reset: line {}"><span class="line">{}"#,
         start.line - 1,
-        " ".repeat(start.col.to_usize())
+        indent_to_initial_start_col,
     )?;
     span_viewables.sort_unstable_by(|a, b| {
         let a = a.span;
@@ -163,14 +172,43 @@ where
         }
         .unwrap()
     });
-    let mut ordered_span_viewables = span_viewables.iter().peekable();
+    let mut ordered_viewables = &span_viewables[..];
+    const LOWEST_VIEWABLE_LAYER: usize = 1;
     let mut alt = false;
-    while ordered_span_viewables.peek().is_some() {
-        next_pos = write_span_viewables(tcx, next_pos, &mut ordered_span_viewables, false, 1, w)?;
-        alt = !alt;
+    while ordered_viewables.len() > 0 {
+        debug!(
+            "calling write_next_viewable with from_pos={}, end_pos={}, and viewables len={}",
+            from_pos.to_usize(),
+            end_pos.to_usize(),
+            ordered_viewables.len()
+        );
+        let (next_from_pos, next_ordered_viewables) = write_next_viewable_with_overlaps(
+            tcx,
+            from_pos,
+            end_pos,
+            ordered_viewables,
+            alt,
+            LOWEST_VIEWABLE_LAYER,
+            w,
+        )?;
+        debug!(
+            "DONE calling write_next_viewable, with new from_pos={}, \
+             and remaining viewables len={}",
+            next_from_pos.to_usize(),
+            next_ordered_viewables.len()
+        );
+        assert!(
+            from_pos != next_from_pos || ordered_viewables.len() != next_ordered_viewables.len(),
+            "write_next_viewable_with_overlaps() must make a state change"
+        );
+        from_pos = next_from_pos;
+        if next_ordered_viewables.len() != ordered_viewables.len() {
+            ordered_viewables = next_ordered_viewables;
+            alt = !alt;
+        }
     }
-    if next_pos < end_pos {
-        write_coverage_gap(tcx, next_pos, end_pos, w)?;
+    if from_pos < end_pos {
+        write_coverage_gap(tcx, from_pos, end_pos, w)?;
     }
     write!(w, r#"</span></div>"#)?;
     writeln!(w, "{}", FOOTER)?;
@@ -233,9 +271,9 @@ fn statement_span_viewable<'tcx>(
     if !body_span.contains(span) {
         return None;
     }
-    let title = format!("bb{}[{}]", bb.index(), i);
-    let tooltip = tooltip(tcx, &title, span, vec![statement.clone()], &None);
-    Some(SpanViewable { span, title, tooltip })
+    let id = format!("{}[{}]", bb.index(), i);
+    let tooltip = tooltip(tcx, &id, span, vec![statement.clone()], &None);
+    Some(SpanViewable { span, id, tooltip })
 }
 
 fn terminator_span_viewable<'tcx>(
@@ -249,9 +287,9 @@ fn terminator_span_viewable<'tcx>(
     if !body_span.contains(span) {
         return None;
     }
-    let title = format!("bb{}`{}`", bb.index(), terminator_kind_name(term));
-    let tooltip = tooltip(tcx, &title, span, vec![], &data.terminator);
-    Some(SpanViewable { span, title, tooltip })
+    let id = format!("{}:{}", bb.index(), terminator_kind_name(term));
+    let tooltip = tooltip(tcx, &id, span, vec![], &data.terminator);
+    Some(SpanViewable { span, id, tooltip })
 }
 
 fn block_span_viewable<'tcx>(
@@ -264,16 +302,16 @@ fn block_span_viewable<'tcx>(
     if !body_span.contains(span) {
         return None;
     }
-    let title = format!("bb{}", bb.index());
-    let tooltip = tooltip(tcx, &title, span, data.statements.clone(), &data.terminator);
-    Some(SpanViewable { span, title, tooltip })
+    let id = format!("{}", bb.index());
+    let tooltip = tooltip(tcx, &id, span, data.statements.clone(), &data.terminator);
+    Some(SpanViewable { span, id, tooltip })
 }
 
 fn compute_block_span<'tcx>(data: &BasicBlockData<'tcx>, body_span: Span) -> Span {
     let mut span = data.terminator().source_info.span;
     for statement_span in data.statements.iter().map(|statement| statement.source_info.span) {
-        // Only combine Spans from the function's body_span.
-        if body_span.contains(statement_span) {
+        // Only combine Spans from the root context, and within the function's body_span.
+        if statement_span.ctxt() == SyntaxContext::root() && body_span.contains(statement_span) {
             span = span.to(statement_span);
         }
     }
@@ -286,100 +324,217 @@ fn compute_block_span<'tcx>(data: &BasicBlockData<'tcx>, body_span: Span) -> Spa
 /// The `layer` is incremented for each overlap, and the `alt` bool alternates between true
 /// and false, for each adjacent non-overlapping span. Source code between the spans (code
 /// that is not in any coverage region) has neutral styling.
-fn write_span_viewables<'tcx, 'b, W>(
+fn write_next_viewable_with_overlaps<'tcx, 'b, W>(
     tcx: TyCtxt<'tcx>,
-    next_pos: BytePos,
-    ordered_span_viewables: &mut Peekable<impl Iterator<Item = &'b SpanViewable>>,
+    mut from_pos: BytePos,
+    mut to_pos: BytePos,
+    ordered_viewables: &'b [SpanViewable],
     alt: bool,
     layer: usize,
     w: &mut W,
-) -> io::Result<BytePos>
+) -> io::Result<(BytePos, &'b [SpanViewable])>
 where
     W: Write,
 {
-    let span_viewable =
-        ordered_span_viewables.next().expect("ordered_span_viewables should have some");
-    if next_pos < span_viewable.span.lo() {
-        write_coverage_gap(tcx, next_pos, span_viewable.span.lo(), w)?;
+    let debug_indent = "  ".repeat(layer);
+    let (viewable, mut remaining_viewables) =
+        ordered_viewables.split_first().expect("ordered_viewables should have some");
+
+    if from_pos < viewable.span.lo() {
+        debug!(
+            "{}advance from_pos to next SpanViewable (from from_pos={} to viewable.span.lo()={} \
+             of {:?}), with to_pos={}",
+            debug_indent,
+            from_pos.to_usize(),
+            viewable.span.lo().to_usize(),
+            viewable.span,
+            to_pos.to_usize()
+        );
+        let hi = cmp::min(viewable.span.lo(), to_pos);
+        write_coverage_gap(tcx, from_pos, hi, w)?;
+        from_pos = hi;
+        if from_pos < viewable.span.lo() {
+            debug!(
+                "{}EARLY RETURN: stopped before getting to next SpanViewable, at {}",
+                debug_indent,
+                from_pos.to_usize()
+            );
+            return Ok((from_pos, ordered_viewables));
+        }
     }
-    let mut remaining_span = span_viewable.span;
+
+    if from_pos < viewable.span.hi() {
+        // Set to_pos to the end of this `viewable` to ensure the recursive calls stop writing
+        // with room to print the tail.
+        to_pos = cmp::min(viewable.span.hi(), to_pos);
+        debug!(
+            "{}update to_pos (if not closer) to viewable.span.hi()={}; to_pos is now {}",
+            debug_indent,
+            viewable.span.hi().to_usize(),
+            to_pos.to_usize()
+        );
+    }
+
     let mut subalt = false;
-    loop {
-        let next_span_viewable = match ordered_span_viewables.peek() {
-            None => break,
-            Some(span_viewable) => *span_viewable,
+    while remaining_viewables.len() > 0 && remaining_viewables[0].span.overlaps(viewable.span) {
+        let overlapping_viewable = &remaining_viewables[0];
+        debug!("{}overlapping_viewable.span={:?}", debug_indent, overlapping_viewable.span);
+
+        let span =
+            trim_span(viewable.span, from_pos, cmp::min(overlapping_viewable.span.lo(), to_pos));
+        let mut some_html_snippet = if from_pos <= viewable.span.hi() || viewable.span.is_empty() {
+            // `viewable` is not yet fully rendered, so start writing the span, up to either the
+            // `to_pos` or the next `overlapping_viewable`, whichever comes first.
+            debug!(
+                "{}make html_snippet (may not write it if early exit) for partial span {:?} \
+                 of viewable.span {:?}",
+                debug_indent, span, viewable.span
+            );
+            from_pos = span.hi();
+            make_html_snippet(tcx, span, Some(&viewable))
+        } else {
+            None
         };
-        if !next_span_viewable.span.overlaps(remaining_span) {
-            break;
+
+        // Defer writing the HTML snippet (until after early return checks) ONLY for empty spans.
+        // An empty Span with Some(html_snippet) is probably a tail marker. If there is an early
+        // exit, there should be another opportunity to write the tail marker.
+        if !span.is_empty() {
+            if let Some(ref html_snippet) = some_html_snippet {
+                debug!(
+                    "{}write html_snippet for that partial span of viewable.span {:?}",
+                    debug_indent, viewable.span
+                );
+                write_span(html_snippet, &viewable.tooltip, alt, layer, w)?;
+            }
+            some_html_snippet = None;
         }
-        write_span(
-            tcx,
-            remaining_span.until(next_span_viewable.span),
-            Some(span_viewable),
-            alt,
-            layer,
-            w,
-        )?;
-        let next_pos = write_span_viewables(
+
+        if from_pos < overlapping_viewable.span.lo() {
+            debug!(
+                "{}EARLY RETURN: from_pos={} has not yet reached the \
+                 overlapping_viewable.span {:?}",
+                debug_indent,
+                from_pos.to_usize(),
+                overlapping_viewable.span
+            );
+            // must have reached `to_pos` before reaching the start of the
+            // `overlapping_viewable.span`
+            return Ok((from_pos, ordered_viewables));
+        }
+
+        if from_pos == to_pos
+            && !(from_pos == overlapping_viewable.span.lo() && overlapping_viewable.span.is_empty())
+        {
+            debug!(
+                "{}EARLY RETURN: from_pos=to_pos={} and overlapping_viewable.span {:?} is not \
+                 empty, or not from_pos",
+                debug_indent,
+                to_pos.to_usize(),
+                overlapping_viewable.span
+            );
+            // `to_pos` must have occurred before the overlapping viewable. Return
+            // `ordered_viewables` so we can continue rendering the `viewable`, from after the
+            // `to_pos`.
+            return Ok((from_pos, ordered_viewables));
+        }
+
+        if let Some(ref html_snippet) = some_html_snippet {
+            debug!(
+                "{}write html_snippet for that partial span of viewable.span {:?}",
+                debug_indent, viewable.span
+            );
+            write_span(html_snippet, &viewable.tooltip, alt, layer, w)?;
+        }
+
+        debug!(
+            "{}recursively calling write_next_viewable with from_pos={}, to_pos={}, \
+             and viewables len={}",
+            debug_indent,
+            from_pos.to_usize(),
+            to_pos.to_usize(),
+            remaining_viewables.len()
+        );
+        // Write the overlaps (and the overlaps' overlaps, if any) up to `to_pos`.
+        let (next_from_pos, next_remaining_viewables) = write_next_viewable_with_overlaps(
             tcx,
-            next_span_viewable.span.lo(),
-            ordered_span_viewables,
+            from_pos,
+            to_pos,
+            &remaining_viewables,
             subalt,
             layer + 1,
             w,
         )?;
-        subalt = !subalt;
-        if next_pos < remaining_span.hi() {
-            remaining_span = remaining_span.with_lo(next_pos);
-        } else {
-            return Ok(next_pos);
+        debug!(
+            "{}DONE recursively calling write_next_viewable, with new from_pos={}, and remaining \
+             viewables len={}",
+            debug_indent,
+            next_from_pos.to_usize(),
+            next_remaining_viewables.len()
+        );
+        assert!(
+            from_pos != next_from_pos
+                || remaining_viewables.len() != next_remaining_viewables.len(),
+            "write_next_viewable_with_overlaps() must make a state change"
+        );
+        from_pos = next_from_pos;
+        if next_remaining_viewables.len() != remaining_viewables.len() {
+            remaining_viewables = next_remaining_viewables;
+            subalt = !subalt;
+        }
+    }
+    if from_pos <= viewable.span.hi() {
+        let span = trim_span(viewable.span, from_pos, to_pos);
+        debug!(
+            "{}After overlaps, writing (end span?) {:?} of viewable.span {:?}",
+            debug_indent, span, viewable.span
+        );
+        if let Some(ref html_snippet) = make_html_snippet(tcx, span, Some(&viewable)) {
+            from_pos = span.hi();
+            write_span(html_snippet, &viewable.tooltip, alt, layer, w)?;
         }
     }
-    write_span(tcx, remaining_span, Some(span_viewable), alt, layer, w)
+    debug!("{}RETURN: No more overlap", debug_indent);
+    Ok((
+        from_pos,
+        if from_pos < viewable.span.hi() { ordered_viewables } else { remaining_viewables },
+    ))
 }
 
+#[inline(always)]
 fn write_coverage_gap<'tcx, W>(
     tcx: TyCtxt<'tcx>,
     lo: BytePos,
     hi: BytePos,
     w: &mut W,
-) -> io::Result<BytePos>
+) -> io::Result<()>
 where
     W: Write,
 {
-    write_span(tcx, Span::with_root_ctxt(lo, hi), None, false, 0, w)
+    let span = Span::with_root_ctxt(lo, hi);
+    if let Some(ref html_snippet) = make_html_snippet(tcx, span, None) {
+        write_span(html_snippet, "", false, 0, w)
+    } else {
+        Ok(())
+    }
 }
 
-fn write_span<'tcx, W>(
-    tcx: TyCtxt<'tcx>,
-    span: Span,
-    span_viewable: Option<&SpanViewable>,
+fn write_span<W>(
+    html_snippet: &str,
+    tooltip: &str,
     alt: bool,
     layer: usize,
     w: &mut W,
-) -> io::Result<BytePos>
+) -> io::Result<()>
 where
     W: Write,
 {
-    let source_map = tcx.sess.source_map();
-    let snippet = source_map
-        .span_to_snippet(span)
-        .unwrap_or_else(|err| bug!("span_to_snippet error for span {:?}: {:?}", span, err));
-    let labeled_snippet = if let Some(SpanViewable { title, .. }) = span_viewable {
-        if span.is_empty() {
-            format!(r#"<span class="annotation">@{}</span>"#, title)
-        } else {
-            format!(r#"<span class="annotation">@{}:</span> {}"#, title, escape_html(&snippet))
-        }
-    } else {
-        snippet
-    };
-    let maybe_alt = if layer > 0 {
+    let maybe_alt_class = if layer > 0 {
         if alt { " odd" } else { " even" }
     } else {
         ""
     };
-    let maybe_tooltip = if let Some(SpanViewable { tooltip, .. }) = span_viewable {
+    let maybe_title_attr = if !tooltip.is_empty() {
         format!(" title=\"{}\"", escape_attr(tooltip))
     } else {
         "".to_owned()
@@ -387,32 +542,73 @@ where
     if layer == 1 {
         write!(w, "<span>")?;
     }
-    for (i, line) in labeled_snippet.lines().enumerate() {
+    for (i, line) in html_snippet.lines().enumerate() {
         if i > 0 {
             write!(w, "{}", NEW_LINE_SPAN)?;
         }
         write!(
             w,
             r#"<span class="code{}" style="--layer: {}"{}>{}</span>"#,
-            maybe_alt, layer, maybe_tooltip, line
+            maybe_alt_class, layer, maybe_title_attr, line
         )?;
     }
+    // Check for and translate trailing newlines, because `str::lines()` ignores them
+    if html_snippet.ends_with('\n') {
+        write!(w, "{}", NEW_LINE_SPAN)?;
+    }
     if layer == 1 {
         write!(w, "</span>")?;
     }
-    Ok(span.hi())
+    Ok(())
+}
+
+fn make_html_snippet<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    span: Span,
+    some_viewable: Option<&SpanViewable>,
+) -> Option<String> {
+    let source_map = tcx.sess.source_map();
+    let snippet = source_map
+        .span_to_snippet(span)
+        .unwrap_or_else(|err| bug!("span_to_snippet error for span {:?}: {:?}", span, err));
+    let html_snippet = if let Some(viewable) = some_viewable {
+        let is_head = span.lo() == viewable.span.lo();
+        let is_tail = span.hi() == viewable.span.hi();
+        let mut labeled_snippet = if is_head {
+            format!(r#"<span class="annotation">{}{}</span>"#, viewable.id, ANNOTATION_LEFT_BRACKET)
+        } else {
+            "".to_owned()
+        };
+        if span.is_empty() {
+            if is_head && is_tail {
+                labeled_snippet.push(CARET);
+            }
+        } else {
+            labeled_snippet.push_str(&escape_html(&snippet));
+        };
+        if is_tail {
+            labeled_snippet.push_str(&format!(
+                r#"<span class="annotation">{}{}</span>"#,
+                ANNOTATION_RIGHT_BRACKET, viewable.id
+            ));
+        }
+        labeled_snippet
+    } else {
+        escape_html(&snippet)
+    };
+    if html_snippet.is_empty() { None } else { Some(html_snippet) }
 }
 
 fn tooltip<'tcx>(
     tcx: TyCtxt<'tcx>,
-    title: &str,
+    spanview_id: &str,
     span: Span,
     statements: Vec<Statement<'tcx>>,
     terminator: &Option<Terminator<'tcx>>,
 ) -> String {
     let source_map = tcx.sess.source_map();
     let mut text = Vec::new();
-    text.push(format!("{}: {}:", title, &source_map.span_to_string(span)));
+    text.push(format!("{}: {}:", spanview_id, &source_map.span_to_string(span)));
     for statement in statements {
         let source_range = source_range_no_file(tcx, &statement.source_info.span);
         text.push(format!(
@@ -436,10 +632,25 @@ fn tooltip<'tcx>(
     text.join("")
 }
 
+fn trim_span(span: Span, from_pos: BytePos, to_pos: BytePos) -> Span {
+    trim_span_hi(trim_span_lo(span, from_pos), to_pos)
+}
+
+fn trim_span_lo(span: Span, from_pos: BytePos) -> Span {
+    if from_pos <= span.lo() { span } else { span.with_lo(cmp::min(span.hi(), from_pos)) }
+}
+
+fn trim_span_hi(span: Span, to_pos: BytePos) -> Span {
+    if to_pos >= span.hi() { span } else { span.with_hi(cmp::max(span.lo(), to_pos)) }
+}
+
 fn fn_span<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Span {
     let hir_id =
         tcx.hir().local_def_id_to_hir_id(def_id.as_local().expect("expected DefId is local"));
-    tcx.hir().span(hir_id)
+    let fn_decl_span = tcx.hir().span(hir_id);
+    let body_span = hir_body(tcx, def_id).value.span;
+    debug_assert_eq!(fn_decl_span.ctxt(), body_span.ctxt());
+    fn_decl_span.to(body_span)
 }
 
 fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> {
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 8cb6b6553ff..a10754f2c0c 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1387,7 +1387,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
                         }
                     }
                 }
-                introduce_suggestion.push((*for_span, for_sugg.to_string()));
+                introduce_suggestion.push((*for_span, for_sugg));
                 introduce_suggestion.push((span, formatter(&lt_name)));
                 err.multipart_suggestion(&msg, introduce_suggestion, Applicability::MaybeIncorrect);
             }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 50729086ec6..848f1c116eb 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -2413,7 +2413,14 @@ impl<'a> Resolver<'a> {
                             (format!("maybe a missing crate `{}`?", ident), None)
                         }
                     } else if i == 0 {
-                        (format!("use of undeclared type or module `{}`", ident), None)
+                        if ident
+                            .name
+                            .with(|n| n.chars().next().map_or(false, |c| c.is_ascii_uppercase()))
+                        {
+                            (format!("use of undeclared type `{}`", ident), None)
+                        } else {
+                            (format!("use of undeclared crate or module `{}`", ident), None)
+                        }
                     } else {
                         let mut msg =
                             format!("could not find `{}` in `{}`", ident, path[i - 1].ident);
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index ad36fa76986..848c7cb7d75 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -850,6 +850,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "enable the experimental Chalk-based trait solving engine"),
     codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
         "the backend to use"),
+    combine_cgu: bool = (false, parse_bool, [TRACKED],
+        "combine CGUs into a single one"),
     crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
         "inject the given attribute in the crate"),
     debug_macros: bool = (false, parse_bool, [TRACKED],
diff --git a/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs b/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs
index fd55a0fc6a1..fcb2af0005f 100644
--- a/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs
+++ b/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs
@@ -22,7 +22,7 @@ pub fn opts() -> TargetOptions {
         "-lmingw32".to_string(),
     ];
     late_link_args.insert(LinkerFlavor::Gcc, mingw_libs.clone());
-    late_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), mingw_libs.clone());
+    late_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), mingw_libs);
 
     TargetOptions {
         executables: false,