about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml1
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs21
-rw-r--r--compiler/rustc_error_codes/src/error_codes.rs2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0625.md28
-rw-r--r--compiler/rustc_errors/src/lib.rs17
-rw-r--r--compiler/rustc_interface/src/tests.rs3
-rw-r--r--compiler/rustc_metadata/src/creader.rs10
-rw-r--r--compiler/rustc_metadata/src/locator.rs4
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs34
-rw-r--r--compiler/rustc_passes/src/liveness.rs5
-rw-r--r--compiler/rustc_session/src/options.rs6
-rw-r--r--compiler/rustc_session/src/session.rs4
-rw-r--r--compiler/rustc_typeck/src/astconv/generics.rs1
-rw-r--r--compiler/rustc_typeck/src/check/dropck.rs13
-rw-r--r--library/core/src/internal_macros.rs1
-rw-r--r--library/core/src/lib.rs120
-rw-r--r--library/std/src/os/linux/process.rs15
-rw-r--r--library/std/src/process.rs4
-rw-r--r--library/std/src/sys/unix/thread.rs11
-rw-r--r--src/bootstrap/bootstrap.py12
-rw-r--r--src/doc/rustc/src/platform-support.md2
-rw-r--r--src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md11
-rw-r--r--src/librustdoc/clean/blanket_impl.rs2
-rw-r--r--src/librustdoc/clean/inline.rs2
-rw-r--r--src/librustdoc/clean/mod.rs3
-rw-r--r--src/librustdoc/clean/types.rs11
-rw-r--r--src/librustdoc/config.rs12
-rw-r--r--src/librustdoc/html/format.rs18
-rw-r--r--src/librustdoc/html/highlight.rs232
-rw-r--r--src/librustdoc/html/highlight/fixtures/highlight.html4
-rw-r--r--src/librustdoc/html/highlight/fixtures/sample.html2
-rw-r--r--src/librustdoc/html/highlight/tests.rs18
-rw-r--r--src/librustdoc/html/markdown.rs1
-rw-r--r--src/librustdoc/html/render/context.rs70
-rw-r--r--src/librustdoc/html/render/mod.rs2
-rw-r--r--src/librustdoc/html/render/print_item.rs3
-rw-r--r--src/librustdoc/html/render/span_map.rs164
-rw-r--r--src/librustdoc/html/render/write_shared.rs4
-rw-r--r--src/librustdoc/html/sources.rs172
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css4
-rw-r--r--src/librustdoc/lib.rs7
-rw-r--r--src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.rs6
-rw-r--r--src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.stderr2
-rw-r--r--src/test/rustdoc-ui/generate-link-to-definition-opt.rs6
-rw-r--r--src/test/rustdoc-ui/generate-link-to-definition-opt.stderr2
-rw-r--r--src/test/rustdoc-ui/generate-link-to-definition-opt2.rs6
-rw-r--r--src/test/rustdoc-ui/generate-link-to-definition-opt2.stderr2
-rw-r--r--src/test/rustdoc/auxiliary/source-code-bar.rs17
-rw-r--r--src/test/rustdoc/auxiliary/source_code.rs1
-rw-r--r--src/test/rustdoc/check-source-code-urls-to-def.rs44
-rw-r--r--src/test/ui/asm/naked-functions-ffi.rs12
-rw-r--r--src/test/ui/asm/naked-functions-ffi.stderr20
-rw-r--r--src/test/ui/asm/naked-functions-unused.rs81
-rw-r--r--src/test/ui/asm/naked-functions-unused.stderr69
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/drop_impl.rs16
-rw-r--r--src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr6
-rw-r--r--src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/issue-87718.rs9
-rw-r--r--src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.rs8
-rw-r--r--src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.stderr21
-rw-r--r--src/test/ui/thread-local-in-ctfe.stderr1
-rw-r--r--src/test/ui/thread-local-static.stderr2
62 files changed, 1123 insertions, 265 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 39688b7b7ea..76a71d8994d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3649,6 +3649,7 @@ dependencies = [
  "libc",
  "object 0.25.2",
  "pathdiff",
+ "regex",
  "rustc_apfloat",
  "rustc_ast",
  "rustc_attr",
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index 554fabaaf6e..0e036a432ad 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -16,6 +16,7 @@ jobserver = "0.1.22"
 tempfile = "3.2"
 pathdiff = "0.2.0"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
+regex = "1.4"
 
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_ast = { path = "../rustc_ast" }
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index ab211e9daff..f3eb1e04d07 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -32,6 +32,7 @@ use cc::windows_registry;
 use object::elf;
 use object::write::Object;
 use object::{Architecture, BinaryFormat, Endianness, FileFlags, SectionFlags, SectionKind};
+use regex::Regex;
 use tempfile::Builder as TempFileBuilder;
 
 use std::ffi::OsString;
@@ -672,6 +673,8 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
     // Invoke the system linker
     info!("{:?}", &cmd);
     let retry_on_segfault = env::var("RUSTC_RETRY_LINKER_ON_SEGFAULT").is_ok();
+    let unknown_arg_regex =
+        Regex::new(r"(unknown|unrecognized) (command line )?(option|argument)").unwrap();
     let mut prog;
     let mut i = 0;
     loop {
@@ -688,16 +691,15 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
         out.extend(&output.stdout);
         let out = String::from_utf8_lossy(&out);
 
-        // Check to see if the link failed with "unrecognized command line option:
-        // '-no-pie'" for gcc or "unknown argument: '-no-pie'" for clang. If so,
-        // reperform the link step without the -no-pie option. This is safe because
-        // if the linker doesn't support -no-pie then it should not default to
-        // linking executables as pie. Different versions of gcc seem to use
-        // different quotes in the error message so don't check for them.
+        // Check to see if the link failed with an error message that indicates it
+        // doesn't recognize the -no-pie option. If so, reperform the link step
+        // without it. This is safe because if the linker doesn't support -no-pie
+        // then it should not default to linking executables as pie. Different
+        // versions of gcc seem to use different quotes in the error message so
+        // don't check for them.
         if sess.target.linker_is_gnu
             && flavor != LinkerFlavor::Ld
-            && (out.contains("unrecognized command line option")
-                || out.contains("unknown argument"))
+            && unknown_arg_regex.is_match(&out)
             && out.contains("-no-pie")
             && cmd.get_args().iter().any(|e| e.to_string_lossy() == "-no-pie")
         {
@@ -716,8 +718,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
         // Fallback from '-static-pie' to '-static' in that case.
         if sess.target.linker_is_gnu
             && flavor != LinkerFlavor::Ld
-            && (out.contains("unrecognized command line option")
-                || out.contains("unknown argument"))
+            && unknown_arg_regex.is_match(&out)
             && (out.contains("-static-pie") || out.contains("--no-dynamic-linker"))
             && cmd.get_args().iter().any(|e| e.to_string_lossy() == "-static-pie")
         {
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index 65999ba707c..719c2c6768b 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -359,6 +359,7 @@ E0621: include_str!("./error_codes/E0621.md"),
 E0622: include_str!("./error_codes/E0622.md"),
 E0623: include_str!("./error_codes/E0623.md"),
 E0624: include_str!("./error_codes/E0624.md"),
+E0625: include_str!("./error_codes/E0625.md"),
 E0626: include_str!("./error_codes/E0626.md"),
 E0627: include_str!("./error_codes/E0627.md"),
 E0628: include_str!("./error_codes/E0628.md"),
@@ -622,7 +623,6 @@ E0783: include_str!("./error_codes/E0783.md"),
 //  E0611, // merged into E0616
 //  E0612, // merged into E0609
 //  E0613, // Removed (merged with E0609)
-    E0625, // thread-local statics cannot be accessed at compile-time
 //  E0629, // missing 'feature' (rustc_const_unstable)
 //  E0630, // rustc_const_unstable attribute must be paired with stable/unstable
            // attribute
diff --git a/compiler/rustc_error_codes/src/error_codes/E0625.md b/compiler/rustc_error_codes/src/error_codes/E0625.md
new file mode 100644
index 00000000000..7db857723cc
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0625.md
@@ -0,0 +1,28 @@
+A compile-time const variable is referring to a thread-local static variable.
+
+Erroneous code example:
+
+```compile_fail,E0625
+#![feature(thread_local)]
+
+#[thread_local]
+static X: usize = 12;
+
+const Y: usize = 2 * X;
+```
+
+Static and const variables can refer to other const variables but a const
+variable cannot refer to a thread-local static variable. In this example,
+`Y` cannot refer to `X`. To fix this, the value can be extracted as a const
+and then used:
+
+```
+#![feature(thread_local)]
+
+const C: usize = 12;
+
+#[thread_local]
+static X: usize = C;
+
+const Y: usize = 2 * C;
+```
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 993a7c2c162..fc0924ac5f9 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -342,6 +342,9 @@ struct HandlerInner {
     deduplicated_warn_count: usize,
 
     future_breakage_diagnostics: Vec<Diagnostic>,
+
+    /// If set to `true`, no warning or error will be emitted.
+    quiet: bool,
 }
 
 /// A key denoting where from a diagnostic was stashed.
@@ -456,10 +459,19 @@ impl Handler {
                 emitted_diagnostics: Default::default(),
                 stashed_diagnostics: Default::default(),
                 future_breakage_diagnostics: Vec::new(),
+                quiet: false,
             }),
         }
     }
 
+    pub fn with_disabled_diagnostic<T, F: FnOnce() -> T>(&self, f: F) -> T {
+        let prev = self.inner.borrow_mut().quiet;
+        self.inner.borrow_mut().quiet = true;
+        let ret = f();
+        self.inner.borrow_mut().quiet = prev;
+        ret
+    }
+
     // This is here to not allow mutation of flags;
     // as of this writing it's only used in tests in librustc_middle.
     pub fn can_emit_warnings(&self) -> bool {
@@ -818,7 +830,7 @@ impl HandlerInner {
     }
 
     fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) {
-        if diagnostic.cancelled() {
+        if diagnostic.cancelled() || self.quiet {
             return;
         }
 
@@ -1035,6 +1047,9 @@ impl HandlerInner {
     }
 
     fn delay_as_bug(&mut self, diagnostic: Diagnostic) {
+        if self.quiet {
+            return;
+        }
         if self.flags.report_delayed_bugs {
             self.emit_diagnostic(&diagnostic);
         }
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index de0d5fb0097..b8961434006 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -740,6 +740,7 @@ fn test_debugging_options_tracking_hash() {
     tracked!(new_llvm_pass_manager, Some(true));
     tracked!(no_generate_arange_section, true);
     tracked!(no_link, true);
+    tracked!(no_profiler_runtime, true);
     tracked!(osx_rpath_install_name, true);
     tracked!(panic_abort_tests, true);
     tracked!(plt, Some(true));
@@ -748,7 +749,7 @@ fn test_debugging_options_tracking_hash() {
     tracked!(print_fuel, Some("abc".to_string()));
     tracked!(profile, true);
     tracked!(profile_emit, Some(PathBuf::from("abc")));
-    tracked!(profiler_runtime, None);
+    tracked!(profiler_runtime, "abc".to_string());
     tracked!(relax_elf_relocations, Some(true));
     tracked!(relro_level, Some(RelroLevel::Full));
     tracked!(simulate_remapped_rust_src_base, Some(PathBuf::from("/rustc/abc")));
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 5373169bda7..394cb838935 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -777,19 +777,17 @@ impl<'a> CrateLoader<'a> {
     }
 
     fn inject_profiler_runtime(&mut self, krate: &ast::Crate) {
-        let profiler_runtime = &self.sess.opts.debugging_opts.profiler_runtime;
-
-        if !(profiler_runtime.is_some()
-            && (self.sess.instrument_coverage()
+        if self.sess.opts.debugging_opts.no_profiler_runtime
+            || !(self.sess.instrument_coverage()
                 || self.sess.opts.debugging_opts.profile
-                || self.sess.opts.cg.profile_generate.enabled()))
+                || self.sess.opts.cg.profile_generate.enabled())
         {
             return;
         }
 
         info!("loading profiler");
 
-        let name = Symbol::intern(profiler_runtime.as_ref().unwrap());
+        let name = Symbol::intern(&self.sess.opts.debugging_opts.profiler_runtime);
         if name == sym::profiler_builtins && self.sess.contains_name(&krate.attrs, sym::no_core) {
             self.sess.err(
                 "`profiler_builtins` crate (required by compiler options) \
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index 4936b22c7b9..cf8577a26cf 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -1103,8 +1103,8 @@ impl CrateError {
                         if sess.is_nightly_build() {
                             err.help("consider building the standard library from source with `cargo build -Zbuild-std`");
                         }
-                    } else if Some(crate_name)
-                        == sess.opts.debugging_opts.profiler_runtime.as_deref().map(Symbol::intern)
+                    } else if crate_name
+                        == Symbol::intern(&sess.opts.debugging_opts.profiler_runtime)
                     {
                         err.note(&"the compiler may have been built without the profiler runtime");
                     }
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index d27ce6ec81a..42e4fc3839e 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -456,27 +456,25 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                     return; // we have already visited everything by now
                 }
             }
-            ExprKind::Borrow { borrow_kind, arg } => match borrow_kind {
-                BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => {
-                    if !self.thir[arg]
-                        .ty
-                        .is_freeze(self.tcx.at(self.thir[arg].span), self.param_env)
-                    {
-                        let mut visitor = LayoutConstrainedPlaceVisitor::new(self.thir, self.tcx);
-                        visit::walk_expr(&mut visitor, expr);
-                        if visitor.found {
-                            self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField);
+            ExprKind::Borrow { borrow_kind, arg } => {
+                let mut visitor = LayoutConstrainedPlaceVisitor::new(self.thir, self.tcx);
+                visit::walk_expr(&mut visitor, expr);
+                if visitor.found {
+                    match borrow_kind {
+                        BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique
+                            if !self.thir[arg]
+                                .ty
+                                .is_freeze(self.tcx.at(self.thir[arg].span), self.param_env) =>
+                        {
+                            self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField)
                         }
+                        BorrowKind::Mut { .. } => {
+                            self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField)
+                        }
+                        BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => {}
                     }
                 }
-                BorrowKind::Mut { .. } => {
-                    let mut visitor = LayoutConstrainedPlaceVisitor::new(self.thir, self.tcx);
-                    visit::walk_expr(&mut visitor, expr);
-                    if visitor.found {
-                        self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField);
-                    }
-                }
-            },
+            }
             _ => {}
         }
         visit::walk_expr(self, expr);
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 4ceefa17bcf..f2c2521ab43 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -332,6 +332,11 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
             }
         }
 
+        // Don't run unused pass for #[naked]
+        if self.tcx.has_attr(def_id, sym::naked) {
+            return;
+        }
+
         if let Some(captures) = maps.tcx.typeck(local_def_id).closure_min_captures.get(&def_id) {
             for &var_hir_id in captures.keys() {
                 let var_name = maps.tcx.hir().name(var_hir_id);
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index ec23a0769af..95a7b0994b8 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1172,6 +1172,8 @@ options! {
         "compile without linking"),
     no_parallel_llvm: bool = (false, parse_no_flag, [UNTRACKED],
         "run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"),
+    no_profiler_runtime: bool = (false, parse_no_flag, [TRACKED],
+        "prevent automatic injection of the profiler_builtins crate"),
     normalize_docs: bool = (false, parse_bool, [TRACKED],
         "normalize associated items in rustdoc when generating documentation"),
     osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
@@ -1217,8 +1219,8 @@ options! {
     profile_emit: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
         "file path to emit profiling data at runtime when using 'profile' \
         (default based on relative source path)"),
-    profiler_runtime: Option<String> = (Some(String::from("profiler_builtins")), parse_opt_string, [TRACKED],
-        "name of the profiler runtime crate to automatically inject, or None to disable"),
+    profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED],
+        "name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)"),
     query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
         "enable queries of the dependency graph for regression testing (default: no)"),
     query_stats: bool = (false, parse_bool, [UNTRACKED],
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 9ab6dbb1ea9..fe87867d299 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -500,6 +500,10 @@ impl Session {
         &self.parse_sess.span_diagnostic
     }
 
+    pub fn with_disabled_diagnostic<T, F: FnOnce() -> T>(&self, f: F) -> T {
+        self.parse_sess.span_diagnostic.with_disabled_diagnostic(f)
+    }
+
     /// Analogous to calling methods on the given `DiagnosticBuilder`, but
     /// deduplicates on lint ID, span (if any), and message for this `Session`
     fn diag_once<'a, 'b>(
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index 0cfdde26c2b..fd0544a47bb 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -613,7 +613,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 param_counts.consts + named_type_param_count
                     - default_counts.types
                     - default_counts.consts
-                    - synth_type_param_count
             };
             debug!("expected_min: {:?}", expected_min);
             debug!("arg_counts.lifetimes: {:?}", gen_args.num_lifetime_params());
diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs
index 01276495c18..17f5020300d 100644
--- a/compiler/rustc_typeck/src/check/dropck.rs
+++ b/compiler/rustc_typeck/src/check/dropck.rs
@@ -218,9 +218,9 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
 
         // This closure is a more robust way to check `Predicate` equality
         // than simple `==` checks (which were the previous implementation).
-        // It relies on `ty::relate` for `TraitPredicate` and `ProjectionPredicate`
-        // (which implement the Relate trait), while delegating on simple equality
-        // for the other `Predicate`.
+        // It relies on `ty::relate` for `TraitPredicate`, `ProjectionPredicate`,
+        // `ConstEvaluatable` and `TypeOutlives` (which implement the Relate trait),
+        // while delegating on simple equality for the other `Predicate`.
         // This implementation solves (Issue #59497) and (Issue #58311).
         // It is unclear to me at the moment whether the approach based on `relate`
         // could be extended easily also to the other `Predicate`.
@@ -235,6 +235,13 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
                 (ty::PredicateKind::Projection(a), ty::PredicateKind::Projection(b)) => {
                     relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
                 }
+                (
+                    ty::PredicateKind::ConstEvaluatable(def_a, substs_a),
+                    ty::PredicateKind::ConstEvaluatable(def_b, substs_b),
+                ) => tcx.try_unify_abstract_consts(((def_a, substs_a), (def_b, substs_b))),
+                (ty::PredicateKind::TypeOutlives(a), ty::PredicateKind::TypeOutlives(b)) => {
+                    relator.relate(predicate.rebind(a.0), p.rebind(b.0)).is_ok()
+                }
                 _ => predicate == p,
             }
         };
diff --git a/library/core/src/internal_macros.rs b/library/core/src/internal_macros.rs
index 4ea7dfc0735..be12f904640 100644
--- a/library/core/src/internal_macros.rs
+++ b/library/core/src/internal_macros.rs
@@ -77,7 +77,6 @@ macro_rules! forward_ref_op_assign {
 }
 
 /// Create a zero-size type similar to a closure type, but named.
-#[unstable(feature = "std_internals", issue = "none")]
 macro_rules! impl_fn_for_zst {
     ($(
         $( #[$attr: meta] )*
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 1ab7227933b..222ef34b6aa 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -61,61 +61,74 @@
     test(attr(allow(dead_code, deprecated, unused_variables, unused_mut)))
 )]
 #![no_core]
+//
+// Lints:
+#![deny(rust_2021_incompatible_or_patterns)]
+#![deny(unsafe_op_in_unsafe_fn)]
 #![warn(deprecated_in_future)]
-#![warn(missing_docs)]
 #![warn(missing_debug_implementations)]
+#![warn(missing_docs)]
 #![allow(explicit_outlives_requirements)]
-#![feature(rustc_allow_const_fn_unstable)]
-#![feature(allow_internal_unstable)]
-#![feature(arbitrary_self_types)]
-#![feature(asm)]
-#![feature(bool_to_option)]
-#![feature(cfg_target_has_atomic)]
-#![feature(const_heap)]
+//
+// Library features for const fns:
+#![feature(const_align_of_val)]
 #![feature(const_alloc_layout)]
 #![feature(const_arguments_as_str)]
 #![feature(const_assert_type)]
-#![feature(const_discriminant)]
+#![feature(const_caller_location)]
 #![feature(const_cell_into_inner)]
-#![feature(const_intrinsic_copy)]
-#![feature(const_intrinsic_forget)]
-#![feature(const_float_classify)]
+#![feature(const_discriminant)]
 #![feature(const_float_bits_conv)]
-#![feature(const_int_unchecked_arith)]
+#![feature(const_float_classify)]
+#![feature(const_heap)]
 #![feature(const_inherent_unchecked_arith)]
-#![feature(const_mut_refs)]
-#![feature(const_refs_to_cell)]
-#![feature(const_panic)]
-#![feature(const_pin)]
-#![cfg_attr(bootstrap, feature(const_fn_union))]
-#![feature(const_impl_trait)]
-#![feature(const_fn_floating_point_arithmetic)]
-#![feature(const_fn_fn_ptr_basics)]
-#![feature(const_fn_trait_bound)]
+#![feature(const_int_unchecked_arith)]
+#![feature(const_intrinsic_copy)]
+#![feature(const_intrinsic_forget)]
+#![feature(const_likely)]
+#![feature(const_maybe_uninit_as_ptr)]
+#![feature(const_maybe_uninit_assume_init)]
 #![feature(const_option)]
-#![feature(const_precise_live_drops)]
+#![feature(const_pin)]
 #![feature(const_ptr_offset)]
 #![feature(const_ptr_offset_from)]
 #![feature(const_ptr_read)]
 #![feature(const_ptr_write)]
 #![feature(const_raw_ptr_comparison)]
-#![feature(const_raw_ptr_deref)]
+#![feature(const_size_of_val)]
 #![feature(const_slice_from_raw_parts)]
 #![feature(const_slice_ptr_len)]
-#![feature(const_size_of_val)]
 #![feature(const_swap)]
-#![feature(const_align_of_val)]
 #![feature(const_type_id)]
 #![feature(const_type_name)]
-#![feature(const_likely)]
 #![feature(const_unreachable_unchecked)]
-#![feature(const_maybe_uninit_assume_init)]
-#![feature(const_maybe_uninit_as_ptr)]
-#![feature(custom_inner_attributes)]
+#![feature(duration_consts_2)]
+#![feature(ptr_metadata)]
+#![feature(slice_ptr_get)]
+#![feature(variant_count)]
+//
+// Language features:
+#![feature(abi_unadjusted)]
+#![feature(allow_internal_unstable)]
+#![feature(asm)]
+#![feature(associated_type_bounds)]
+#![feature(auto_traits)]
+#![feature(cfg_target_has_atomic)]
+#![feature(const_fn_floating_point_arithmetic)]
+#![feature(const_fn_fn_ptr_basics)]
+#![feature(const_fn_trait_bound)]
+#![cfg_attr(bootstrap, feature(const_fn_transmute))]
+#![cfg_attr(bootstrap, feature(const_fn_union))]
+#![feature(const_impl_trait)]
+#![feature(const_mut_refs)]
+#![feature(const_panic)]
+#![feature(const_precise_live_drops)]
+#![feature(const_raw_ptr_deref)]
+#![feature(const_refs_to_cell)]
 #![feature(decl_macro)]
 #![feature(doc_cfg)]
 #![feature(doc_notable_trait)]
-#![feature(duration_consts_2)]
+#![feature(exhaustive_patterns)]
 #![feature(extern_types)]
 #![feature(fundamental)]
 #![feature(intra_doc_pointers)]
@@ -123,53 +136,40 @@
 #![feature(lang_items)]
 #![feature(link_llvm_intrinsics)]
 #![feature(llvm_asm)]
+#![feature(min_specialization)]
 #![feature(negative_impls)]
 #![feature(never_type)]
-#![feature(nll)]
-#![feature(exhaustive_patterns)]
 #![feature(no_core)]
-#![feature(auto_traits)]
-#![feature(pin_deref_mut)]
+#![feature(no_coverage)] // rust-lang/rust#84605
+#![feature(no_niche)] // rust-lang/rust#68303
+#![feature(platform_intrinsics)]
 #![feature(prelude_import)]
-#![feature(ptr_metadata)]
-#![feature(repr_simd, platform_intrinsics)]
+#![feature(repr_simd)]
+#![feature(rustc_allow_const_fn_unstable)]
 #![feature(rustc_attrs)]
 #![feature(simd_ffi)]
-#![feature(min_specialization)]
 #![feature(staged_api)]
-#![feature(std_internals)]
 #![feature(stmt_expr_attributes)]
-#![feature(str_split_as_str)]
-#![feature(str_split_inclusive_as_str)]
-#![feature(char_indices_offset)]
 #![feature(trait_alias)]
 #![feature(transparent_unions)]
 #![feature(try_blocks)]
 #![feature(unboxed_closures)]
 #![feature(unsized_fn_params)]
-#![feature(variant_count)]
-#![feature(tbm_target_feature)]
-#![feature(sse4a_target_feature)]
-#![feature(arm_target_feature)]
-#![feature(powerpc_target_feature)]
-#![feature(mips_target_feature)]
+//
+// Target features:
 #![feature(aarch64_target_feature)]
-#![feature(wasm_target_feature)]
+#![feature(adx_target_feature)]
+#![feature(arm_target_feature)]
 #![feature(avx512_target_feature)]
 #![feature(cmpxchg16b_target_feature)]
-#![feature(rtm_target_feature)]
 #![feature(f16c_target_feature)]
 #![feature(hexagon_target_feature)]
-#![cfg_attr(bootstrap, feature(const_fn_transmute))]
-#![feature(abi_unadjusted)]
-#![feature(adx_target_feature)]
-#![feature(associated_type_bounds)]
-#![feature(const_caller_location)]
-#![feature(slice_ptr_get)]
-#![feature(no_niche)] // rust-lang/rust#68303
-#![feature(no_coverage)] // rust-lang/rust#84605
-#![deny(unsafe_op_in_unsafe_fn)]
-#![deny(rust_2021_incompatible_or_patterns)]
+#![feature(mips_target_feature)]
+#![feature(powerpc_target_feature)]
+#![feature(rtm_target_feature)]
+#![feature(sse4a_target_feature)]
+#![feature(tbm_target_feature)]
+#![feature(wasm_target_feature)]
 
 // allow using `core::` in intra-doc links
 #[allow(unused_extern_crates)]
diff --git a/library/std/src/os/linux/process.rs b/library/std/src/os/linux/process.rs
index 91547b8f916..6daff0f003c 100644
--- a/library/std/src/os/linux/process.rs
+++ b/library/std/src/os/linux/process.rs
@@ -5,6 +5,7 @@
 use crate::io::Result;
 use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
 use crate::process;
+use crate::sealed::Sealed;
 #[cfg(not(doc))]
 use crate::sys::fd::FileDesc;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
@@ -84,15 +85,10 @@ impl IntoRawFd for PidFd {
     }
 }
 
-mod private_child_ext {
-    pub trait Sealed {}
-    impl Sealed for crate::process::Child {}
-}
-
 /// Os-specific extensions for [`Child`]
 ///
 /// [`Child`]: process::Child
-pub trait ChildExt: private_child_ext::Sealed {
+pub trait ChildExt: Sealed {
     /// Obtains a reference to the [`PidFd`] created for this [`Child`], if available.
     ///
     /// A pidfd will only be available if its creation was requested with
@@ -120,15 +116,10 @@ pub trait ChildExt: private_child_ext::Sealed {
     fn take_pidfd(&mut self) -> Result<PidFd>;
 }
 
-mod private_command_ext {
-    pub trait Sealed {}
-    impl Sealed for crate::process::Command {}
-}
-
 /// Os-specific extensions for [`Command`]
 ///
 /// [`Command`]: process::Command
-pub trait CommandExt: private_command_ext::Sealed {
+pub trait CommandExt: Sealed {
     /// Sets whether a [`PidFd`](struct@PidFd) should be created for the [`Child`]
     /// spawned by this [`Command`].
     /// By default, no pidfd will be created.
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 99c3369425b..d3e271df8d8 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -205,6 +205,10 @@ pub struct Child {
     pub stderr: Option<ChildStderr>,
 }
 
+/// Allows extension traits within `std`.
+#[unstable(feature = "sealed", issue = "none")]
+impl crate::sealed::Sealed for Child {}
+
 impl AsInner<imp::Process> for Child {
     fn as_inner(&self) -> &imp::Process {
         &self.handle
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 1488bf94841..bc61f472a2b 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -164,16 +164,23 @@ impl Thread {
         }
     }
 
+    #[cfg(target_os = "haiku")]
+    pub fn set_name(name: &CStr) {
+        unsafe {
+            let thread_self = libc::find_thread(ptr::null_mut());
+            libc::rename_thread(thread_self, name.as_ptr());
+        }
+    }
+
     #[cfg(any(
         target_env = "newlib",
-        target_os = "haiku",
         target_os = "l4re",
         target_os = "emscripten",
         target_os = "redox",
         target_os = "vxworks"
     ))]
     pub fn set_name(_name: &CStr) {
-        // Newlib, Haiku, Emscripten, and VxWorks have no way to set a thread name.
+        // Newlib, Emscripten, and VxWorks have no way to set a thread name.
     }
 
     pub fn sleep(dur: Duration) {
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index f2e38a7eab6..3faf38c66ec 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -464,7 +464,8 @@ class RustBuild(object):
             # LLVM more often than necessary.
             #
             # This git command finds that commit SHA, looking for bors-authored
-            # merges that modified src/llvm-project.
+            # merges that modified src/llvm-project or other relevant version
+            # stamp files.
             #
             # This works even in a repository that has not yet initialized
             # submodules.
@@ -472,8 +473,8 @@ class RustBuild(object):
                 "git", "rev-parse", "--show-toplevel",
             ]).decode(sys.getdefaultencoding()).strip()
             llvm_sha = subprocess.check_output([
-                "git", "log", "--author=bors", "--format=%H", "-n1",
-                "--no-patch", "--first-parent",
+                "git", "rev-list", "--author=bors@rust-lang.org", "-n1",
+                "--merges", "--first-parent", "HEAD",
                 "--",
                 "{}/src/llvm-project".format(top_level),
                 "{}/src/bootstrap/download-ci-llvm-stamp".format(top_level),
@@ -665,7 +666,10 @@ class RustBuild(object):
 
         # Look for a version to compare to based on the current commit.
         # Only commits merged by bors will have CI artifacts.
-        merge_base = ["git", "log", "--author=bors", "--pretty=%H", "-n1"]
+        merge_base = [
+            "git", "rev-list", "--author=bors@rust-lang.org", "-n1",
+            "--merges", "--first-parent", "HEAD"
+        ]
         commit = subprocess.check_output(merge_base, universal_newlines=True).strip()
 
         # Warn if there were changes to the compiler or standard library since the ancestor commit.
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 90ef48798dd..b265760dc57 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -165,6 +165,7 @@ target | std | notes
 `wasm32-unknown-unknown` | ✓ | WebAssembly
 `wasm32-wasi` | ✓ | WebAssembly with WASI
 `x86_64-apple-ios` | ✓ | 64-bit x86 iOS
+[`aarch64-apple-ios-sim`](platform-support/aarch64-apple-ios-sim.md) | ✓ |  | Apple iOS Simulator on ARM64
 `x86_64-fortanix-unknown-sgx` | ✓ | [Fortanix ABI] for 64-bit Intel SGX
 `x86_64-fuchsia` | ✓ | 64-bit Fuchsia
 `x86_64-linux-android` | ✓ | 64-bit x86 Android
@@ -196,7 +197,6 @@ host tools.
 target | std | host | notes
 -------|:---:|:----:|-------
 `aarch64-apple-ios-macabi` | ? |  | Apple Catalyst on ARM64
-[`aarch64-apple-ios-sim`](platform-support/aarch64-apple-ios-sim.md) | ✓ |  | Apple iOS Simulator on ARM64
 `aarch64-apple-tvos` | * |  | ARM64 tvOS
 `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
 `aarch64-unknown-hermit` | ? |  |
diff --git a/src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md b/src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md
index 9aa5db26f91..3f29e2c5e1f 100644
--- a/src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md
+++ b/src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md
@@ -1,6 +1,6 @@
 # aarch64-apple-ios-sim
 
-**Tier: 3**
+**Tier: 2**
 
 Apple iOS Simulator on ARM64.
 
@@ -39,17 +39,16 @@ Currently there is no support to run the rustc test suite for this target.
 
 *Note: Building for this target requires the corresponding iOS SDK, as provided by Xcode 12+.*
 
-If `rustc` has support for that target and the library artifacts are available,
-then Rust programs can be built for that target:
+From Rust Nightly 1.56.0 (2021-08-03) on the artifacts are shipped pre-compiled:
 
 ```text
-rustc --target aarch64-apple-ios-sim your-code.rs
+rustup target add aarch64-apple-ios-sim --toolchain nightly
 ```
 
-On Rust Nightly it is possible to build without the target artifacts available:
+Rust programs can be built for that target:
 
 ```text
-cargo build -Z build-std --target aarch64-apple-ios-sim
+rustc --target aarch64-apple-ios-sim your-code.rs
 ```
 
 There is no easy way to run simple programs in the iOS simulator.
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 8f74a48547d..207c89cbfe8 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -98,7 +98,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                     visibility: Inherited,
                     def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
                     kind: box ImplItem(Impl {
-                        span: Span::from_rustc_span(self.cx.tcx.def_span(impl_def_id)),
+                        span: Span::new(self.cx.tcx.def_span(impl_def_id)),
                         unsafety: hir::Unsafety::Normal,
                         generics: (
                             self.cx.tcx.generics_of(impl_def_id),
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index b3b89e6e673..43979423ae6 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -517,7 +517,7 @@ fn build_module(
         }
     }
 
-    let span = clean::Span::from_rustc_span(cx.tcx.def_span(did));
+    let span = clean::Span::new(cx.tcx.def_span(did));
     clean::Module { items, span }
 }
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index b3fc1e73f78..3d65fcedaf4 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -95,7 +95,8 @@ impl Clean<Item> for doctree::Module<'_> {
 
         // determine if we should display the inner contents or
         // the outer `mod` item for the source code.
-        let span = Span::from_rustc_span({
+
+        let span = Span::new({
             let where_outer = self.where_outer(cx.tcx);
             let sm = cx.sess().source_map();
             let outer = sm.lookup_char_pos(where_outer.lo());
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 5c73d3de5b9..22e4d21c87b 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -343,7 +343,7 @@ crate struct Item {
 rustc_data_structures::static_assert_size!(Item, 56);
 
 crate fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
-    Span::from_rustc_span(def_id.as_local().map_or_else(
+    Span::new(def_id.as_local().map_or_else(
         || tcx.def_span(def_id),
         |local| {
             let hir = tcx.hir();
@@ -1943,10 +1943,11 @@ crate enum Variant {
 crate struct Span(rustc_span::Span);
 
 impl Span {
-    crate fn from_rustc_span(sp: rustc_span::Span) -> Self {
-        // Get the macro invocation instead of the definition,
-        // in case the span is result of a macro expansion.
-        // (See rust-lang/rust#39726)
+    /// Wraps a [`rustc_span::Span`]. In case this span is the result of a macro expansion, the
+    /// span will be updated to point to the macro invocation instead of the macro definition.
+    ///
+    /// (See rust-lang/rust#39726)
+    crate fn new(sp: rustc_span::Span) -> Self {
         Self(sp.source_callsite())
     }
 
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index abd1fd2bf39..e44158bc042 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -276,6 +276,8 @@ crate struct RenderOptions {
     crate show_type_layout: bool,
     crate unstable_features: rustc_feature::UnstableFeatures,
     crate emit: Vec<EmitType>,
+    /// If `true`, HTML source pages will generate links for items to their definition.
+    crate generate_link_to_definition: bool,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -655,6 +657,15 @@ impl Options {
         let generate_redirect_map = matches.opt_present("generate-redirect-map");
         let show_type_layout = matches.opt_present("show-type-layout");
         let nocapture = matches.opt_present("nocapture");
+        let generate_link_to_definition = matches.opt_present("generate-link-to-definition");
+
+        if generate_link_to_definition && (show_coverage || output_format != OutputFormat::Html) {
+            diag.struct_err(
+                "--generate-link-to-definition option can only be used with HTML output format",
+            )
+            .emit();
+            return Err(1);
+        }
 
         let (lint_opts, describe_lints, lint_cap) =
             get_cmd_lint_options(matches, error_format, &debugging_opts);
@@ -721,6 +732,7 @@ impl Options {
                     crate_name.as_deref(),
                 ),
                 emit,
+                generate_link_to_definition,
             },
             crate_name,
             output_format,
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 8ab6aa775d2..eb7c12d13c3 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -484,7 +484,11 @@ crate enum HrefError {
     NotInExternalCache,
 }
 
-crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec<String>), HrefError> {
+crate fn href_with_root_path(
+    did: DefId,
+    cx: &Context<'_>,
+    root_path: Option<&str>,
+) -> Result<(String, ItemType, Vec<String>), HrefError> {
     let cache = &cx.cache();
     let relative_to = &cx.current;
     fn to_module_fqp(shortty: ItemType, fqp: &[String]) -> &[String] {
@@ -495,6 +499,7 @@ crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec<Str
         return Err(HrefError::Private);
     }
 
+    let mut is_remote = false;
     let (fqp, shortty, mut url_parts) = match cache.paths.get(&did) {
         Some(&(ref fqp, shortty)) => (fqp, shortty, {
             let module_fqp = to_module_fqp(shortty, fqp);
@@ -508,6 +513,7 @@ crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec<Str
                     shortty,
                     match cache.extern_locations[&did.krate] {
                         ExternalLocation::Remote(ref s) => {
+                            is_remote = true;
                             let s = s.trim_end_matches('/');
                             let mut s = vec![s];
                             s.extend(module_fqp[..].iter().map(String::as_str));
@@ -522,6 +528,12 @@ crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec<Str
             }
         }
     };
+    if !is_remote {
+        if let Some(root_path) = root_path {
+            let root = root_path.trim_end_matches('/');
+            url_parts.insert(0, root);
+        }
+    }
     let last = &fqp.last().unwrap()[..];
     let filename;
     match shortty {
@@ -536,6 +548,10 @@ crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec<Str
     Ok((url_parts.join("/"), shortty, fqp.to_vec()))
 }
 
+crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec<String>), HrefError> {
+    href_with_root_path(did, cx, None)
+}
+
 /// Both paths should only be modules.
 /// This is because modules get their own directories; that is, `std::vec` and `std::vec::Vec` will
 /// both need `../iter/trait.Iterator.html` to get at the iterator trait.
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 33b1d98313c..3cdb1352bef 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -6,15 +6,28 @@
 //! Use the `render_with_highlighting` to highlight some rust code.
 
 use crate::html::escape::Escape;
+use crate::html::render::Context;
 
-use std::fmt::Display;
+use std::fmt::{Display, Write};
 use std::iter::Peekable;
 
 use rustc_lexer::{LiteralKind, TokenKind};
 use rustc_span::edition::Edition;
 use rustc_span::symbol::Symbol;
-
-use super::format::Buffer;
+use rustc_span::{BytePos, Span, DUMMY_SP};
+
+use super::format::{self, Buffer};
+use super::render::LinkFromSrc;
+
+/// This type is needed in case we want to render links on items to allow to go to their definition.
+crate struct ContextInfo<'a, 'b, 'c> {
+    crate context: &'a Context<'b>,
+    /// This span contains the current file we're going through.
+    crate file_span: Span,
+    /// This field is used to know "how far" from the top of the directory we are to link to either
+    /// documentation pages or other source pages.
+    crate root_path: &'c str,
+}
 
 /// Highlights `src`, returning the HTML output.
 crate fn render_with_highlighting(
@@ -25,6 +38,7 @@ crate fn render_with_highlighting(
     tooltip: Option<(Option<Edition>, &str)>,
     edition: Edition,
     extra_content: Option<Buffer>,
+    context_info: Option<ContextInfo<'_, '_, '_>>,
 ) {
     debug!("highlighting: ================\n{}\n==============", src);
     if let Some((edition_info, class)) = tooltip {
@@ -41,7 +55,7 @@ crate fn render_with_highlighting(
     }
 
     write_header(out, class, extra_content);
-    write_code(out, &src, edition);
+    write_code(out, &src, edition, context_info);
     write_footer(out, playground_button);
 }
 
@@ -57,16 +71,33 @@ fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buf
     }
 }
 
-fn write_code(out: &mut Buffer, src: &str, edition: Edition) {
+/// Convert the given `src` source code into HTML by adding classes for highlighting.
+///
+/// This code is used to render code blocks (in the documentation) as well as the source code pages.
+///
+/// Some explanations on the last arguments:
+///
+/// In case we are rendering a code block and not a source code file, `context_info` will be `None`.
+/// To put it more simply: if `context_info` is `None`, the code won't try to generate links to an
+/// item definition.
+///
+/// More explanations about spans and how we use them here are provided in the
+fn write_code(
+    out: &mut Buffer,
+    src: &str,
+    edition: Edition,
+    context_info: Option<ContextInfo<'_, '_, '_>>,
+) {
     // This replace allows to fix how the code source with DOS backline characters is displayed.
     let src = src.replace("\r\n", "\n");
-    Classifier::new(&src, edition).highlight(&mut |highlight| {
-        match highlight {
-            Highlight::Token { text, class } => string(out, Escape(text), class),
-            Highlight::EnterSpan { class } => enter_span(out, class),
-            Highlight::ExitSpan => exit_span(out),
-        };
-    });
+    Classifier::new(&src, edition, context_info.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP))
+        .highlight(&mut |highlight| {
+            match highlight {
+                Highlight::Token { text, class } => string(out, Escape(text), class, &context_info),
+                Highlight::EnterSpan { class } => enter_span(out, class),
+                Highlight::ExitSpan => exit_span(out),
+            };
+        });
 }
 
 fn write_footer(out: &mut Buffer, playground_button: Option<&str>) {
@@ -82,14 +113,14 @@ enum Class {
     KeyWord,
     // Keywords that do pointer/reference stuff.
     RefKeyWord,
-    Self_,
+    Self_(Span),
     Op,
     Macro,
     MacroNonTerminal,
     String,
     Number,
     Bool,
-    Ident,
+    Ident(Span),
     Lifetime,
     PreludeTy,
     PreludeVal,
@@ -105,20 +136,29 @@ impl Class {
             Class::Attribute => "attribute",
             Class::KeyWord => "kw",
             Class::RefKeyWord => "kw-2",
-            Class::Self_ => "self",
+            Class::Self_(_) => "self",
             Class::Op => "op",
             Class::Macro => "macro",
             Class::MacroNonTerminal => "macro-nonterminal",
             Class::String => "string",
             Class::Number => "number",
             Class::Bool => "bool-val",
-            Class::Ident => "ident",
+            Class::Ident(_) => "ident",
             Class::Lifetime => "lifetime",
             Class::PreludeTy => "prelude-ty",
             Class::PreludeVal => "prelude-val",
             Class::QuestionMark => "question-mark",
         }
     }
+
+    /// In case this is an item which can be converted into a link to a definition, it'll contain
+    /// a "span" (a tuple representing `(lo, hi)` equivalent of `Span`).
+    fn get_span(self) -> Option<Span> {
+        match self {
+            Self::Ident(sp) | Self::Self_(sp) => Some(sp),
+            _ => None,
+        }
+    }
 }
 
 enum Highlight<'a> {
@@ -144,14 +184,19 @@ impl Iterator for TokenIter<'a> {
     }
 }
 
-fn get_real_ident_class(text: &str, edition: Edition) -> Class {
-    match text {
+/// Classifies into identifier class; returns `None` if this is a non-keyword identifier.
+fn get_real_ident_class(text: &str, edition: Edition, allow_path_keywords: bool) -> Option<Class> {
+    let ignore: &[&str] =
+        if allow_path_keywords { &["self", "Self", "super", "crate"] } else { &["self", "Self"] };
+    if ignore.iter().any(|k| *k == text) {
+        return None;
+    }
+    Some(match text {
         "ref" | "mut" => Class::RefKeyWord,
-        "self" | "Self" => Class::Self_,
         "false" | "true" => Class::Bool,
         _ if Symbol::intern(text).is_reserved(|| edition) => Class::KeyWord,
-        _ => Class::Ident,
-    }
+        _ => return None,
+    })
 }
 
 /// Processes program tokens, classifying strings of text by highlighting
@@ -163,11 +208,14 @@ struct Classifier<'a> {
     in_macro_nonterminal: bool,
     edition: Edition,
     byte_pos: u32,
+    file_span: Span,
     src: &'a str,
 }
 
 impl<'a> Classifier<'a> {
-    fn new(src: &str, edition: Edition) -> Classifier<'_> {
+    /// Takes as argument the source code to HTML-ify, the rust edition to use and the source code
+    /// file span which will be used later on by the `span_correspondance_map`.
+    fn new(src: &str, edition: Edition, file_span: Span) -> Classifier<'_> {
         let tokens = TokenIter { src }.peekable();
         Classifier {
             tokens,
@@ -176,10 +224,18 @@ impl<'a> Classifier<'a> {
             in_macro_nonterminal: false,
             edition,
             byte_pos: 0,
+            file_span,
             src,
         }
     }
 
+    /// Convenient wrapper to create a [`Span`] from a position in the file.
+    fn new_span(&self, lo: u32, text: &str) -> Span {
+        let hi = lo + text.len() as u32;
+        let file_lo = self.file_span.lo();
+        self.file_span.with_lo(file_lo + BytePos(lo)).with_hi(file_lo + BytePos(hi))
+    }
+
     /// Concatenate colons and idents as one when possible.
     fn get_full_ident_path(&mut self) -> Vec<(TokenKind, usize, usize)> {
         let start = self.byte_pos as usize;
@@ -201,17 +257,17 @@ impl<'a> Classifier<'a> {
                 if has_ident {
                     return vec![(TokenKind::Ident, start, pos), (TokenKind::Colon, pos, pos + nb)];
                 } else {
-                    return vec![(TokenKind::Colon, pos, pos + nb)];
+                    return vec![(TokenKind::Colon, start, pos + nb)];
                 }
             }
 
-            if let Some((Class::Ident, text)) = self.tokens.peek().map(|(token, text)| {
+            if let Some((None, text)) = self.tokens.peek().map(|(token, text)| {
                 if *token == TokenKind::Ident {
-                    let class = get_real_ident_class(text, edition);
+                    let class = get_real_ident_class(text, edition, true);
                     (class, text)
                 } else {
                     // Doesn't matter which Class we put in here...
-                    (Class::Comment, text)
+                    (Some(Class::Comment), text)
                 }
             }) {
                 // We only "add" the colon if there is an ident behind.
@@ -221,7 +277,7 @@ impl<'a> Classifier<'a> {
             } else if nb > 0 && has_ident {
                 return vec![(TokenKind::Ident, start, pos), (TokenKind::Colon, pos, pos + nb)];
             } else if nb > 0 {
-                return vec![(TokenKind::Colon, pos, pos + nb)];
+                return vec![(TokenKind::Colon, start, start + nb)];
             } else if has_ident {
                 return vec![(TokenKind::Ident, start, pos)];
             } else {
@@ -230,11 +286,15 @@ impl<'a> Classifier<'a> {
         }
     }
 
-    /// Wraps the tokens iteration to ensure that the byte_pos is always correct.
-    fn next(&mut self) -> Option<(TokenKind, &'a str)> {
+    /// Wraps the tokens iteration to ensure that the `byte_pos` is always correct.
+    ///
+    /// It returns the token's kind, the token as a string and its byte position in the source
+    /// string.
+    fn next(&mut self) -> Option<(TokenKind, &'a str, u32)> {
         if let Some((kind, text)) = self.tokens.next() {
+            let before = self.byte_pos;
             self.byte_pos += text.len() as u32;
-            Some((kind, text))
+            Some((kind, text, before))
         } else {
             None
         }
@@ -254,23 +314,36 @@ impl<'a> Classifier<'a> {
                 .unwrap_or(false)
             {
                 let tokens = self.get_full_ident_path();
-                for (token, start, end) in tokens {
-                    let text = &self.src[start..end];
-                    self.advance(token, text, sink);
+                for (token, start, end) in &tokens {
+                    let text = &self.src[*start..*end];
+                    self.advance(*token, text, sink, *start as u32);
                     self.byte_pos += text.len() as u32;
                 }
+                if !tokens.is_empty() {
+                    continue;
+                }
             }
-            if let Some((token, text)) = self.next() {
-                self.advance(token, text, sink);
+            if let Some((token, text, before)) = self.next() {
+                self.advance(token, text, sink, before);
             } else {
                 break;
             }
         }
     }
 
-    /// Single step of highlighting. This will classify `token`, but maybe also
-    /// a couple of following ones as well.
-    fn advance(&mut self, token: TokenKind, text: &'a str, sink: &mut dyn FnMut(Highlight<'a>)) {
+    /// Single step of highlighting. This will classify `token`, but maybe also a couple of
+    /// following ones as well.
+    ///
+    /// `before` is the position of the given token in the `source` string and is used as "lo" byte
+    /// in case we want to try to generate a link for this token using the
+    /// `span_correspondance_map`.
+    fn advance(
+        &mut self,
+        token: TokenKind,
+        text: &'a str,
+        sink: &mut dyn FnMut(Highlight<'a>),
+        before: u32,
+    ) {
         let lookahead = self.peek();
         let no_highlight = |sink: &mut dyn FnMut(_)| sink(Highlight::Token { text, class: None });
         let class = match token {
@@ -401,19 +474,22 @@ impl<'a> Classifier<'a> {
                 sink(Highlight::Token { text, class: None });
                 return;
             }
-            TokenKind::Ident => match get_real_ident_class(text, self.edition) {
-                Class::Ident => match text {
+            TokenKind::Ident => match get_real_ident_class(text, self.edition, false) {
+                None => match text {
                     "Option" | "Result" => Class::PreludeTy,
                     "Some" | "None" | "Ok" | "Err" => Class::PreludeVal,
                     _ if self.in_macro_nonterminal => {
                         self.in_macro_nonterminal = false;
                         Class::MacroNonTerminal
                     }
-                    _ => Class::Ident,
+                    "self" | "Self" => Class::Self_(self.new_span(before, text)),
+                    _ => Class::Ident(self.new_span(before, text)),
                 },
-                c => c,
+                Some(c) => c,
             },
-            TokenKind::RawIdent | TokenKind::UnknownPrefix => Class::Ident,
+            TokenKind::RawIdent | TokenKind::UnknownPrefix => {
+                Class::Ident(self.new_span(before, text))
+            }
             TokenKind::Lifetime { .. } => Class::Lifetime,
         };
         // Anything that didn't return above is the simple case where we the
@@ -446,13 +522,75 @@ fn exit_span(out: &mut Buffer) {
 ///     enter_span(Foo), string("text", None), exit_span()
 ///     string("text", Foo)
 /// ```
+///
 /// The latter can be thought of as a shorthand for the former, which is more
 /// flexible.
-fn string<T: Display>(out: &mut Buffer, text: T, klass: Option<Class>) {
-    match klass {
-        None => write!(out, "{}", text),
-        Some(klass) => write!(out, "<span class=\"{}\">{}</span>", klass.as_html(), text),
+///
+/// Note that if `context` is not `None` and that the given `klass` contains a `Span`, the function
+/// will then try to find this `span` in the `span_correspondance_map`. If found, it'll then
+/// generate a link for this element (which corresponds to where its definition is located).
+fn string<T: Display>(
+    out: &mut Buffer,
+    text: T,
+    klass: Option<Class>,
+    context_info: &Option<ContextInfo<'_, '_, '_>>,
+) {
+    let klass = match klass {
+        None => return write!(out, "{}", text),
+        Some(klass) => klass,
+    };
+    let def_span = match klass.get_span() {
+        Some(d) => d,
+        None => {
+            write!(out, "<span class=\"{}\">{}</span>", klass.as_html(), text);
+            return;
+        }
+    };
+    let mut text_s = text.to_string();
+    if text_s.contains("::") {
+        text_s = text_s.split("::").intersperse("::").fold(String::new(), |mut path, t| {
+            match t {
+                "self" | "Self" => write!(
+                    &mut path,
+                    "<span class=\"{}\">{}</span>",
+                    Class::Self_(DUMMY_SP).as_html(),
+                    t
+                ),
+                "crate" | "super" => {
+                    write!(&mut path, "<span class=\"{}\">{}</span>", Class::KeyWord.as_html(), t)
+                }
+                t => write!(&mut path, "{}", t),
+            }
+            .expect("Failed to build source HTML path");
+            path
+        });
+    }
+    if let Some(context_info) = context_info {
+        if let Some(href) =
+            context_info.context.shared.span_correspondance_map.get(&def_span).and_then(|href| {
+                let context = context_info.context;
+                // FIXME: later on, it'd be nice to provide two links (if possible) for all items:
+                // one to the documentation page and one to the source definition.
+                // FIXME: currently, external items only generate a link to their documentation,
+                // a link to their definition can be generated using this:
+                // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
+                match href {
+                    LinkFromSrc::Local(span) => context
+                        .href_from_span(*span)
+                        .map(|s| format!("{}{}", context_info.root_path, s)),
+                    LinkFromSrc::External(def_id) => {
+                        format::href_with_root_path(*def_id, context, Some(context_info.root_path))
+                            .ok()
+                            .map(|(url, _, _)| url)
+                    }
+                }
+            })
+        {
+            write!(out, "<a class=\"{}\" href=\"{}\">{}</a>", klass.as_html(), href, text_s);
+            return;
+        }
     }
+    write!(out, "<span class=\"{}\">{}</span>", klass.as_html(), text_s);
 }
 
 #[cfg(test)]
diff --git a/src/librustdoc/html/highlight/fixtures/highlight.html b/src/librustdoc/html/highlight/fixtures/highlight.html
new file mode 100644
index 00000000000..abc2db1790c
--- /dev/null
+++ b/src/librustdoc/html/highlight/fixtures/highlight.html
@@ -0,0 +1,4 @@
+<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::a::foo</span>;
+<span class="kw">use</span> <span class="ident"><span class="self">self</span>::whatever</span>;
+<span class="kw">let</span> <span class="ident">x</span> <span class="op">=</span> <span class="ident"><span class="kw">super</span>::b::foo</span>;
+<span class="kw">let</span> <span class="ident">y</span> <span class="op">=</span> <span class="ident"><span class="self">Self</span>::whatever</span>;
\ No newline at end of file
diff --git a/src/librustdoc/html/highlight/fixtures/sample.html b/src/librustdoc/html/highlight/fixtures/sample.html
index 8d23477bbcb..866caea9256 100644
--- a/src/librustdoc/html/highlight/fixtures/sample.html
+++ b/src/librustdoc/html/highlight/fixtures/sample.html
@@ -23,7 +23,7 @@
     <span class="macro">assert!</span>(<span class="self">self</span>.<span class="ident">length</span> <span class="op">&lt;</span> <span class="ident">N</span> <span class="op">&amp;&amp;</span> <span class="ident">index</span> <span class="op">&lt;</span><span class="op">=</span> <span class="self">self</span>.<span class="ident">length</span>);
     <span class="ident">::std::env::var</span>(<span class="string">&quot;gateau&quot;</span>).<span class="ident">is_ok</span>();
     <span class="attribute">#[<span class="ident">rustfmt::skip</span>]</span>
-    <span class="kw">let</span> <span class="ident">s</span>:<span class="ident">std</span><span class="ident">::path::PathBuf</span> <span class="op">=</span> <span class="ident">std::path::PathBuf::new</span>();
+    <span class="kw">let</span> <span class="ident">s</span>:<span class="ident">std::path::PathBuf</span> <span class="op">=</span> <span class="ident">std::path::PathBuf::new</span>();
     <span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">s</span> <span class="op">=</span> <span class="ident">String::new</span>();
 
     <span class="kw">match</span> <span class="kw-2">&amp;</span><span class="ident">s</span> {
diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs
index a505865b149..68592ae96c1 100644
--- a/src/librustdoc/html/highlight/tests.rs
+++ b/src/librustdoc/html/highlight/tests.rs
@@ -22,7 +22,7 @@ fn test_html_highlighting() {
         let src = include_str!("fixtures/sample.rs");
         let html = {
             let mut out = Buffer::new();
-            write_code(&mut out, src, Edition::Edition2018);
+            write_code(&mut out, src, Edition::Edition2018, None);
             format!("{}<pre><code>{}</code></pre>\n", STYLE, out.into_inner())
         };
         expect_file!["fixtures/sample.html"].assert_eq(&html);
@@ -36,7 +36,21 @@ fn test_dos_backline() {
     println!(\"foo\");\r\n\
 }\r\n";
         let mut html = Buffer::new();
-        write_code(&mut html, src, Edition::Edition2018);
+        write_code(&mut html, src, Edition::Edition2018, None);
         expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner());
     });
 }
+
+#[test]
+fn test_keyword_highlight() {
+    create_default_session_globals_then(|| {
+        let src = "use crate::a::foo;
+use self::whatever;
+let x = super::b::foo;
+let y = Self::whatever;";
+
+        let mut html = Buffer::new();
+        write_code(&mut html, src, Edition::Edition2018, None);
+        expect_file!["fixtures/highlight.html"].assert_eq(&html.into_inner());
+    });
+}
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index b8756d2526e..472323daf30 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -330,6 +330,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
             tooltip,
             edition,
             None,
+            None,
         );
         Some(Event::Html(s.into_inner().into()))
     }
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index b6c3220901f..6ce0828e159 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -17,7 +17,10 @@ use rustc_span::symbol::sym;
 use super::cache::{build_index, ExternalLocation};
 use super::print_item::{full_path, item_path, print_item};
 use super::write_shared::write_shared;
-use super::{print_sidebar, settings, AllTypes, NameDoc, StylePath, BASIC_KEYWORDS};
+use super::{
+    collect_spans_and_sources, print_sidebar, settings, AllTypes, LinkFromSrc, NameDoc, StylePath,
+    BASIC_KEYWORDS,
+};
 
 use crate::clean;
 use crate::clean::ExternalCrate;
@@ -46,7 +49,7 @@ crate struct Context<'tcx> {
     pub(crate) current: Vec<String>,
     /// The current destination folder of where HTML artifacts should be placed.
     /// This changes as the context descends into the module hierarchy.
-    pub(super) dst: PathBuf,
+    crate dst: PathBuf,
     /// A flag, which when `true`, will render pages which redirect to the
     /// real location of an item. This is used to allow external links to
     /// publicly reused items to redirect to the right location.
@@ -58,7 +61,7 @@ crate struct Context<'tcx> {
     /// Issue for improving the situation: [#82381][]
     ///
     /// [#82381]: https://github.com/rust-lang/rust/issues/82381
-    pub(super) shared: Rc<SharedContext<'tcx>>,
+    crate shared: Rc<SharedContext<'tcx>>,
     /// The [`Cache`] used during rendering.
     ///
     /// Ideally the cache would be in [`SharedContext`], but it's mutated
@@ -68,7 +71,11 @@ crate struct Context<'tcx> {
     /// It's immutable once in `Context`, so it's not as bad that it's not in
     /// `SharedContext`.
     // FIXME: move `cache` to `SharedContext`
-    pub(super) cache: Rc<Cache>,
+    crate cache: Rc<Cache>,
+    /// This flag indicates whether `[src]` links should be generated or not. If
+    /// the source files are present in the html rendering, then this will be
+    /// `true`.
+    crate include_sources: bool,
 }
 
 // `Context` is cloned a lot, so we don't want the size to grow unexpectedly.
@@ -84,10 +91,6 @@ crate struct SharedContext<'tcx> {
     /// This describes the layout of each page, and is not modified after
     /// creation of the context (contains info like the favicon and added html).
     crate layout: layout::Layout,
-    /// This flag indicates whether `[src]` links should be generated or not. If
-    /// the source files are present in the html rendering, then this will be
-    /// `true`.
-    crate include_sources: bool,
     /// The local file sources we've emitted and their respective url-paths.
     crate local_sources: FxHashMap<PathBuf, String>,
     /// Show the memory layout of types in the docs.
@@ -125,6 +128,10 @@ crate struct SharedContext<'tcx> {
     redirections: Option<RefCell<FxHashMap<String, String>>>,
 
     pub(crate) templates: tera::Tera,
+
+    /// Correspondance map used to link types used in the source code pages to allow to click on
+    /// links to jump to the type's definition.
+    crate span_correspondance_map: FxHashMap<rustc_span::Span, LinkFromSrc>,
 }
 
 impl SharedContext<'_> {
@@ -293,15 +300,19 @@ impl<'tcx> Context<'tcx> {
     /// may happen, for example, with externally inlined items where the source
     /// of their crate documentation isn't known.
     pub(super) fn src_href(&self, item: &clean::Item) -> Option<String> {
-        if item.span(self.tcx()).is_dummy() {
+        self.href_from_span(item.span(self.tcx()))
+    }
+
+    crate fn href_from_span(&self, span: clean::Span) -> Option<String> {
+        if span.is_dummy() {
             return None;
         }
         let mut root = self.root_path();
         let mut path = String::new();
-        let cnum = item.span(self.tcx()).cnum(self.sess());
+        let cnum = span.cnum(self.sess());
 
         // We can safely ignore synthetic `SourceFile`s.
-        let file = match item.span(self.tcx()).filename(self.sess()) {
+        let file = match span.filename(self.sess()) {
             FileName::Real(ref path) => path.local_path_if_available().to_path_buf(),
             _ => return None,
         };
@@ -339,8 +350,8 @@ impl<'tcx> Context<'tcx> {
             (&*symbol, &path)
         };
 
-        let loline = item.span(self.tcx()).lo(self.sess()).line;
-        let hiline = item.span(self.tcx()).hi(self.sess()).line;
+        let loline = span.lo(self.sess()).line;
+        let hiline = span.hi(self.sess()).line;
         let lines =
             if loline == hiline { loline.to_string() } else { format!("{}-{}", loline, hiline) };
         Some(format!(
@@ -362,9 +373,9 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
     const RUN_ON_MODULE: bool = true;
 
     fn init(
-        mut krate: clean::Crate,
+        krate: clean::Crate,
         options: RenderOptions,
-        mut cache: Cache,
+        cache: Cache,
         tcx: TyCtxt<'tcx>,
     ) -> Result<(Self, clean::Crate), Error> {
         // need to save a copy of the options for rendering the index page
@@ -385,6 +396,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             unstable_features,
             generate_redirect_map,
             show_type_layout,
+            generate_link_to_definition,
             ..
         } = options;
 
@@ -444,13 +456,21 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
                 _ => {}
             }
         }
+
+        let (mut krate, local_sources, matches) = collect_spans_and_sources(
+            tcx,
+            krate,
+            &src_root,
+            include_sources,
+            generate_link_to_definition,
+        );
+
         let (sender, receiver) = channel();
         let mut scx = SharedContext {
             tcx,
             collapsed: krate.collapsed,
             src_root,
-            include_sources,
-            local_sources: Default::default(),
+            local_sources,
             issue_tracker_base_url,
             layout,
             created_dirs: Default::default(),
@@ -466,6 +486,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             redirections: if generate_redirect_map { Some(Default::default()) } else { None },
             show_type_layout,
             templates,
+            span_correspondance_map: matches,
         };
 
         // Add the default themes to the `Vec` of stylepaths
@@ -483,12 +504,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
 
         let dst = output;
         scx.ensure_dir(&dst)?;
-        if emit_crate {
-            krate = sources::render(&dst, &mut scx, krate)?;
-        }
-
-        // Build our search index
-        let index = build_index(&krate, &mut cache, tcx);
 
         let mut cx = Context {
             current: Vec::new(),
@@ -497,8 +512,16 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             id_map: RefCell::new(id_map),
             shared: Rc::new(scx),
             cache: Rc::new(cache),
+            include_sources,
         };
 
+        if emit_crate {
+            krate = sources::render(&mut cx, krate)?;
+        }
+
+        // Build our search index
+        let index = build_index(&krate, Rc::get_mut(&mut cx.cache).unwrap(), tcx);
+
         // Write shared runs within a flock; disable thread dispatching of IO temporarily.
         Rc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(true);
         write_shared(&cx, &krate, index, &md_opts)?;
@@ -514,6 +537,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             id_map: RefCell::new(IdMap::new()),
             shared: Rc::clone(&self.shared),
             cache: Rc::clone(&self.cache),
+            include_sources: self.include_sources,
         }
     }
 
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index c05ea81ac1f..fd2e18a8be7 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -30,9 +30,11 @@ mod tests;
 
 mod context;
 mod print_item;
+mod span_map;
 mod write_shared;
 
 crate use context::*;
+crate use span_map::{collect_spans_and_sources, LinkFromSrc};
 
 use std::collections::VecDeque;
 use std::default::Default;
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 5c30d8bbd17..f31305c76e6 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -119,7 +119,7 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer,
     // [src] link in the downstream documentation will actually come back to
     // this page, and this link will be auto-clicked. The `id` attribute is
     // used to find the link to auto-click.
-    if cx.shared.include_sources && !item.is_primitive() {
+    if cx.include_sources && !item.is_primitive() {
         write_srclink(cx, item, buf);
     }
 
@@ -1081,6 +1081,7 @@ fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Mac
             None,
             it.span(cx.tcx()).inner().edition(),
             None,
+            None,
         );
     });
     document(w, cx, it, None)
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
new file mode 100644
index 00000000000..b35cd45dc9a
--- /dev/null
+++ b/src/librustdoc/html/render/span_map.rs
@@ -0,0 +1,164 @@
+use crate::clean;
+use crate::html::sources;
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::{ExprKind, GenericParam, GenericParamKind, HirId, Mod, Node};
+use rustc_middle::ty::TyCtxt;
+use rustc_span::Span;
+
+use std::path::{Path, PathBuf};
+
+/// This enum allows us to store two different kinds of information:
+///
+/// In case the `span` definition comes from the same crate, we can simply get the `span` and use
+/// it as is.
+///
+/// Otherwise, we store the definition `DefId` and will generate a link to the documentation page
+/// instead of the source code directly.
+#[derive(Debug)]
+crate enum LinkFromSrc {
+    Local(clean::Span),
+    External(DefId),
+}
+
+/// This function will do at most two things:
+///
+/// 1. Generate a `span` correspondance map which links an item `span` to its definition `span`.
+/// 2. Collect the source code files.
+///
+/// It returns the `krate`, the source code files and the `span` correspondance map.
+///
+/// Note about the `span` correspondance map: the keys are actually `(lo, hi)` of `span`s. We don't
+/// need the `span` context later on, only their position, so instead of keep a whole `Span`, we
+/// only keep the `lo` and `hi`.
+crate fn collect_spans_and_sources(
+    tcx: TyCtxt<'_>,
+    krate: clean::Crate,
+    src_root: &Path,
+    include_sources: bool,
+    generate_link_to_definition: bool,
+) -> (clean::Crate, FxHashMap<PathBuf, String>, FxHashMap<Span, LinkFromSrc>) {
+    let mut visitor = SpanMapVisitor { tcx, matches: FxHashMap::default() };
+
+    if include_sources {
+        if generate_link_to_definition {
+            intravisit::walk_crate(&mut visitor, tcx.hir().krate());
+        }
+        let (krate, sources) = sources::collect_local_sources(tcx, src_root, krate);
+        (krate, sources, visitor.matches)
+    } else {
+        (krate, Default::default(), Default::default())
+    }
+}
+
+struct SpanMapVisitor<'tcx> {
+    crate tcx: TyCtxt<'tcx>,
+    crate matches: FxHashMap<Span, LinkFromSrc>,
+}
+
+impl<'tcx> SpanMapVisitor<'tcx> {
+    /// This function is where we handle `hir::Path` elements and add them into the "span map".
+    fn handle_path(&mut self, path: &rustc_hir::Path<'_>, path_span: Option<Span>) {
+        let info = match path.res {
+            // FIXME: For now, we only handle `DefKind` if it's not `DefKind::TyParam` or
+            // `DefKind::Macro`. Would be nice to support them too alongside the other `DefKind`
+            // (such as primitive types!).
+            Res::Def(kind, def_id) if kind != DefKind::TyParam => {
+                if matches!(kind, DefKind::Macro(_)) {
+                    return;
+                }
+                Some(def_id)
+            }
+            Res::Local(_) => None,
+            Res::Err => return,
+            _ => return,
+        };
+        if let Some(span) = self.tcx.hir().res_span(path.res) {
+            self.matches.insert(
+                path_span.unwrap_or_else(|| path.span),
+                LinkFromSrc::Local(clean::Span::new(span)),
+            );
+        } else if let Some(def_id) = info {
+            self.matches
+                .insert(path_span.unwrap_or_else(|| path.span), LinkFromSrc::External(def_id));
+        }
+    }
+}
+
+impl Visitor<'tcx> for SpanMapVisitor<'tcx> {
+    type Map = rustc_middle::hir::map::Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::All(self.tcx.hir())
+    }
+
+    fn visit_generic_param(&mut self, p: &'tcx GenericParam<'tcx>) {
+        if !matches!(p.kind, GenericParamKind::Type { .. }) {
+            return;
+        }
+        for bound in p.bounds {
+            if let Some(trait_ref) = bound.trait_ref() {
+                self.handle_path(&trait_ref.path, None);
+            }
+        }
+    }
+
+    fn visit_path(&mut self, path: &'tcx rustc_hir::Path<'tcx>, _id: HirId) {
+        self.handle_path(path, None);
+        intravisit::walk_path(self, path);
+    }
+
+    fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: Span, id: HirId) {
+        // To make the difference between "mod foo {}" and "mod foo;". In case we "import" another
+        // file, we want to link to it. Otherwise no need to create a link.
+        if !span.overlaps(m.inner) {
+            // Now that we confirmed it's a file import, we want to get the span for the module
+            // name only and not all the "mod foo;".
+            if let Some(node) = self.tcx.hir().find(id) {
+                match node {
+                    Node::Item(item) => {
+                        self.matches
+                            .insert(item.ident.span, LinkFromSrc::Local(clean::Span::new(m.inner)));
+                    }
+                    _ => {}
+                }
+            }
+        }
+        intravisit::walk_mod(self, m, id);
+    }
+
+    fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) {
+        match expr.kind {
+            ExprKind::MethodCall(segment, method_span, _, _) => {
+                if let Some(hir_id) = segment.hir_id {
+                    let hir = self.tcx.hir();
+                    let body_id = hir.enclosing_body_owner(hir_id);
+                    let typeck_results = self.tcx.sess.with_disabled_diagnostic(|| {
+                        self.tcx.typeck_body(
+                            hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"),
+                        )
+                    });
+                    if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
+                        self.matches.insert(
+                            method_span,
+                            match hir.span_if_local(def_id) {
+                                Some(span) => LinkFromSrc::Local(clean::Span::new(span)),
+                                None => LinkFromSrc::External(def_id),
+                            },
+                        );
+                    }
+                }
+            }
+            _ => {}
+        }
+        intravisit::walk_expr(self, expr);
+    }
+
+    fn visit_use(&mut self, path: &'tcx rustc_hir::Path<'tcx>, id: HirId) {
+        self.handle_path(path, None);
+        intravisit::walk_use(self, path, id);
+    }
+}
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index 4411b7771ed..c16769c474a 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -272,7 +272,7 @@ pub(super) fn write_shared(
     write_minify("search.js", static_files::SEARCH_JS)?;
     write_minify("settings.js", static_files::SETTINGS_JS)?;
 
-    if cx.shared.include_sources {
+    if cx.include_sources {
         write_minify("source-script.js", static_files::sidebar::SOURCE_SCRIPT)?;
     }
 
@@ -398,7 +398,7 @@ pub(super) fn write_shared(
         }
     }
 
-    if cx.shared.include_sources {
+    if cx.include_sources {
         let mut hierarchy = Hierarchy::new(OsString::new());
         for source in cx
             .shared
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 80dd7a7a952..73916e204d9 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -5,8 +5,10 @@ use crate::fold::DocFolder;
 use crate::html::format::Buffer;
 use crate::html::highlight;
 use crate::html::layout;
-use crate::html::render::{SharedContext, BASIC_KEYWORDS};
+use crate::html::render::{Context, BASIC_KEYWORDS};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::LOCAL_CRATE;
+use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::edition::Edition;
 use rustc_span::source_map::FileName;
@@ -14,52 +16,117 @@ use std::ffi::OsStr;
 use std::fs;
 use std::path::{Component, Path, PathBuf};
 
-crate fn render(
-    dst: &Path,
-    scx: &mut SharedContext<'_>,
-    krate: clean::Crate,
-) -> Result<clean::Crate, Error> {
+crate fn render(cx: &mut Context<'_>, krate: clean::Crate) -> Result<clean::Crate, Error> {
     info!("emitting source files");
-    let dst = dst.join("src").join(&*krate.name.as_str());
-    scx.ensure_dir(&dst)?;
-    let mut folder = SourceCollector { dst, scx };
+    let dst = cx.dst.join("src").join(&*krate.name.as_str());
+    cx.shared.ensure_dir(&dst)?;
+    let mut folder = SourceCollector { dst, cx, emitted_local_sources: FxHashSet::default() };
     Ok(folder.fold_crate(krate))
 }
 
+crate fn collect_local_sources<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    src_root: &Path,
+    krate: clean::Crate,
+) -> (clean::Crate, FxHashMap<PathBuf, String>) {
+    let mut lsc = LocalSourcesCollector { tcx, local_sources: FxHashMap::default(), src_root };
+
+    let krate = lsc.fold_crate(krate);
+    (krate, lsc.local_sources)
+}
+
+struct LocalSourcesCollector<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    local_sources: FxHashMap<PathBuf, String>,
+    src_root: &'a Path,
+}
+
+fn is_real_and_local(span: clean::Span, sess: &Session) -> bool {
+    span.filename(sess).is_real() && span.cnum(sess) == LOCAL_CRATE
+}
+
+impl LocalSourcesCollector<'_, '_> {
+    fn add_local_source(&mut self, item: &clean::Item) {
+        let sess = self.tcx.sess;
+        let span = item.span(self.tcx);
+        // skip all synthetic "files"
+        if !is_real_and_local(span, sess) {
+            return;
+        }
+        let filename = span.filename(sess);
+        let p = match filename {
+            FileName::Real(ref file) => match file.local_path() {
+                Some(p) => p.to_path_buf(),
+                _ => return,
+            },
+            _ => return,
+        };
+        if self.local_sources.contains_key(&*p) {
+            // We've already emitted this source
+            return;
+        }
+
+        let mut href = String::new();
+        clean_path(&self.src_root, &p, false, |component| {
+            href.push_str(&component.to_string_lossy());
+            href.push('/');
+        });
+
+        let src_fname = p.file_name().expect("source has no filename").to_os_string();
+        let mut fname = src_fname.clone();
+        fname.push(".html");
+        href.push_str(&fname.to_string_lossy());
+        self.local_sources.insert(p, href);
+    }
+}
+
+impl DocFolder for LocalSourcesCollector<'_, '_> {
+    fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
+        self.add_local_source(&item);
+
+        // FIXME: if `include_sources` isn't set and DocFolder didn't require consuming the crate by value,
+        // we could return None here without having to walk the rest of the crate.
+        Some(self.fold_item_recur(item))
+    }
+}
+
 /// Helper struct to render all source code to HTML pages
 struct SourceCollector<'a, 'tcx> {
-    scx: &'a mut SharedContext<'tcx>,
+    cx: &'a mut Context<'tcx>,
 
     /// Root destination to place all HTML output into
     dst: PathBuf,
+    emitted_local_sources: FxHashSet<PathBuf>,
 }
 
 impl DocFolder for SourceCollector<'_, '_> {
     fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
+        let tcx = self.cx.tcx();
+        let span = item.span(tcx);
+        let sess = tcx.sess;
+
         // If we're not rendering sources, there's nothing to do.
         // If we're including source files, and we haven't seen this file yet,
         // then we need to render it out to the filesystem.
-        if self.scx.include_sources
-            // skip all synthetic "files"
-            && item.span(self.scx.tcx).filename(self.sess()).is_real()
-            // skip non-local files
-            && item.span(self.scx.tcx).cnum(self.sess()) == LOCAL_CRATE
-        {
-            let filename = item.span(self.scx.tcx).filename(self.sess());
+        if self.cx.include_sources && is_real_and_local(span, sess) {
+            let filename = span.filename(sess);
+            let span = span.inner();
+            let pos = sess.source_map().lookup_source_file(span.lo());
+            let file_span = span.with_lo(pos.start_pos).with_hi(pos.end_pos);
             // If it turns out that we couldn't read this file, then we probably
             // can't read any of the files (generating html output from json or
             // something like that), so just don't include sources for the
             // entire crate. The other option is maintaining this mapping on a
             // per-file basis, but that's probably not worth it...
-            self.scx.include_sources = match self.emit_source(&filename) {
+            self.cx.include_sources = match self.emit_source(&filename, file_span) {
                 Ok(()) => true,
                 Err(e) => {
-                    self.scx.tcx.sess.span_err(
-                        item.span(self.scx.tcx).inner(),
+                    self.cx.shared.tcx.sess.span_err(
+                        span,
                         &format!(
                             "failed to render source code for `{}`: {}",
                             filename.prefer_local(),
-                            e
+                            e,
                         ),
                     );
                     false
@@ -73,12 +140,12 @@ impl DocFolder for SourceCollector<'_, '_> {
 }
 
 impl SourceCollector<'_, 'tcx> {
-    fn sess(&self) -> &'tcx Session {
-        &self.scx.tcx.sess
-    }
-
     /// Renders the given filename into its corresponding HTML source file.
-    fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> {
+    fn emit_source(
+        &mut self,
+        filename: &FileName,
+        file_span: rustc_span::Span,
+    ) -> Result<(), Error> {
         let p = match *filename {
             FileName::Real(ref file) => {
                 if let Some(local_path) = file.local_path() {
@@ -89,7 +156,7 @@ impl SourceCollector<'_, 'tcx> {
             }
             _ => return Ok(()),
         };
-        if self.scx.local_sources.contains_key(&*p) {
+        if self.emitted_local_sources.contains(&*p) {
             // We've already emitted this source
             return Ok(());
         }
@@ -107,20 +174,17 @@ impl SourceCollector<'_, 'tcx> {
         // Create the intermediate directories
         let mut cur = self.dst.clone();
         let mut root_path = String::from("../../");
-        let mut href = String::new();
-        clean_path(&self.scx.src_root, &p, false, |component| {
+        clean_path(&self.cx.shared.src_root, &p, false, |component| {
             cur.push(component);
             root_path.push_str("../");
-            href.push_str(&component.to_string_lossy());
-            href.push('/');
         });
-        self.scx.ensure_dir(&cur)?;
+
+        self.cx.shared.ensure_dir(&cur)?;
 
         let src_fname = p.file_name().expect("source has no filename").to_os_string();
         let mut fname = src_fname.clone();
         fname.push(".html");
         cur.push(&fname);
-        href.push_str(&fname.to_string_lossy());
 
         let title = format!("{} - source", src_fname.to_string_lossy());
         let desc = format!("Source of the Rust file `{}`.", filename.prefer_remapped());
@@ -128,23 +192,25 @@ impl SourceCollector<'_, 'tcx> {
             title: &title,
             css_class: "source",
             root_path: &root_path,
-            static_root_path: self.scx.static_root_path.as_deref(),
+            static_root_path: self.cx.shared.static_root_path.as_deref(),
             description: &desc,
             keywords: BASIC_KEYWORDS,
-            resource_suffix: &self.scx.resource_suffix,
-            extra_scripts: &[&format!("source-files{}", self.scx.resource_suffix)],
-            static_extra_scripts: &[&format!("source-script{}", self.scx.resource_suffix)],
+            resource_suffix: &self.cx.shared.resource_suffix,
+            extra_scripts: &[&format!("source-files{}", self.cx.shared.resource_suffix)],
+            static_extra_scripts: &[&format!("source-script{}", self.cx.shared.resource_suffix)],
         };
         let v = layout::render(
-            &self.scx.templates,
-            &self.scx.layout,
+            &self.cx.shared.templates,
+            &self.cx.shared.layout,
             &page,
             "",
-            |buf: &mut _| print_src(buf, contents, self.scx.edition()),
-            &self.scx.style_files,
+            |buf: &mut _| {
+                print_src(buf, contents, self.cx.shared.edition(), file_span, &self.cx, &root_path)
+            },
+            &self.cx.shared.style_files,
         );
-        self.scx.fs.write(&cur, v.as_bytes())?;
-        self.scx.local_sources.insert(p, href);
+        self.cx.shared.fs.write(&cur, v.as_bytes())?;
+        self.emitted_local_sources.insert(p);
         Ok(())
     }
 }
@@ -178,7 +244,14 @@ where
 
 /// Wrapper struct to render the source code of a file. This will do things like
 /// adding line numbers to the left-hand side.
-fn print_src(buf: &mut Buffer, s: &str, edition: Edition) {
+fn print_src(
+    buf: &mut Buffer,
+    s: &str,
+    edition: Edition,
+    file_span: rustc_span::Span,
+    context: &Context<'_>,
+    root_path: &str,
+) {
     let lines = s.lines().count();
     let mut line_numbers = Buffer::empty_from(buf);
     let mut cols = 0;
@@ -192,5 +265,14 @@ fn print_src(buf: &mut Buffer, s: &str, edition: Edition) {
         writeln!(line_numbers, "<span id=\"{0}\">{0:1$}</span>", i, cols);
     }
     line_numbers.write_str("</pre>");
-    highlight::render_with_highlighting(s, buf, None, None, None, edition, Some(line_numbers));
+    highlight::render_with_highlighting(
+        s,
+        buf,
+        None,
+        None,
+        None,
+        edition,
+        Some(line_numbers),
+        Some(highlight::ContextInfo { context, file_span, root_path }),
+    );
 }
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 4e33eab5650..bbc48f49e63 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -450,6 +450,10 @@ nav.sub {
 	border-bottom-left-radius: 5px;
 }
 
+.example-wrap > pre.rust a:hover {
+	text-decoration: underline;
+}
+
 .rustdoc:not(.source) .example-wrap > pre:not(.line-number) {
 	width: 100%;
 	overflow-x: auto;
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index fa755777584..a98725e683c 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -607,6 +607,13 @@ fn opts() -> Vec<RustcOptGroup> {
         unstable("nocapture", |o| {
             o.optflag("", "nocapture", "Don't capture stdout and stderr of tests")
         }),
+        unstable("generate-link-to-definition", |o| {
+            o.optflag(
+                "",
+                "generate-link-to-definition",
+                "Make the identifiers in the HTML source code pages navigable",
+            )
+        }),
     ]
 }
 
diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.rs b/src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.rs
new file mode 100644
index 00000000000..87620d74ee6
--- /dev/null
+++ b/src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.rs
@@ -0,0 +1,6 @@
+// This test purpose is to check that the "--generate-link-to-definition"
+// option can only be used on nightly.
+
+// compile-flags: --generate-link-to-definition
+
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.stderr b/src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.stderr
new file mode 100644
index 00000000000..a8ddf91bcbf
--- /dev/null
+++ b/src/test/rustdoc-ui/generate-link-to-definition-opt-unstable.stderr
@@ -0,0 +1,2 @@
+error: the `-Z unstable-options` flag must also be passed to enable the flag `generate-link-to-definition`
+
diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt.rs b/src/test/rustdoc-ui/generate-link-to-definition-opt.rs
new file mode 100644
index 00000000000..8f4f561b44d
--- /dev/null
+++ b/src/test/rustdoc-ui/generate-link-to-definition-opt.rs
@@ -0,0 +1,6 @@
+// This test purpose is to check that the "--generate-link-to-definition"
+// option can only be used with HTML generation.
+
+// compile-flags: -Zunstable-options --generate-link-to-definition --output-format json
+
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt.stderr b/src/test/rustdoc-ui/generate-link-to-definition-opt.stderr
new file mode 100644
index 00000000000..4c8c607e7da
--- /dev/null
+++ b/src/test/rustdoc-ui/generate-link-to-definition-opt.stderr
@@ -0,0 +1,2 @@
+error: --generate-link-to-definition option can only be used with HTML output format
+
diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt2.rs b/src/test/rustdoc-ui/generate-link-to-definition-opt2.rs
new file mode 100644
index 00000000000..da5142087dd
--- /dev/null
+++ b/src/test/rustdoc-ui/generate-link-to-definition-opt2.rs
@@ -0,0 +1,6 @@
+// This test purpose is to check that the "--generate-link-to-definition"
+// option can only be used with HTML generation.
+
+// compile-flags: -Zunstable-options --generate-link-to-definition --show-coverage
+
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/generate-link-to-definition-opt2.stderr b/src/test/rustdoc-ui/generate-link-to-definition-opt2.stderr
new file mode 100644
index 00000000000..4c8c607e7da
--- /dev/null
+++ b/src/test/rustdoc-ui/generate-link-to-definition-opt2.stderr
@@ -0,0 +1,2 @@
+error: --generate-link-to-definition option can only be used with HTML output format
+
diff --git a/src/test/rustdoc/auxiliary/source-code-bar.rs b/src/test/rustdoc/auxiliary/source-code-bar.rs
new file mode 100644
index 00000000000..8700d688ef7
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/source-code-bar.rs
@@ -0,0 +1,17 @@
+//! just some other file. :)
+
+use crate::Foo;
+
+pub struct Bar {
+    field: Foo,
+}
+
+pub struct Bar2 {
+    field: crate::Foo,
+}
+
+pub mod sub {
+    pub trait Trait {
+        fn tadam() {}
+    }
+}
diff --git a/src/test/rustdoc/auxiliary/source_code.rs b/src/test/rustdoc/auxiliary/source_code.rs
new file mode 100644
index 00000000000..72a5c1a0ae9
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/source_code.rs
@@ -0,0 +1 @@
+pub struct SourceCode;
diff --git a/src/test/rustdoc/check-source-code-urls-to-def.rs b/src/test/rustdoc/check-source-code-urls-to-def.rs
new file mode 100644
index 00000000000..e3ae79ccdb1
--- /dev/null
+++ b/src/test/rustdoc/check-source-code-urls-to-def.rs
@@ -0,0 +1,44 @@
+// compile-flags: -Zunstable-options --generate-link-to-definition
+// aux-build:source_code.rs
+// build-aux-docs
+
+#![crate_name = "foo"]
+
+extern crate source_code;
+
+// @has 'src/foo/check-source-code-urls-to-def.rs.html'
+
+// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#1-17"]' 'bar'
+#[path = "auxiliary/source-code-bar.rs"]
+pub mod bar;
+
+// @count - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#5-7"]' 4
+use bar::Bar;
+// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#13-17"]' 'self'
+// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14-16"]' 'Trait'
+use bar::sub::{self, Trait};
+
+pub struct Foo;
+
+impl Foo {
+    fn hello(&self) {}
+}
+
+fn babar() {}
+
+// @has - '//a/@href' '/struct.String.html'
+// @count - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#21"]' 5
+// @has - '//a[@href="../../source_code/struct.SourceCode.html"]' 'source_code::SourceCode'
+pub fn foo(a: u32, b: &str, c: String, d: Foo, e: bar::Bar, f: source_code::SourceCode) {
+    let x = 12;
+    let y: Foo = Foo;
+    let z: Bar = bar::Bar { field: Foo };
+    babar();
+    // @has - '//a[@href="../../src/foo/check-source-code-urls-to-def.rs.html#24"]' 'hello'
+    y.hello();
+}
+
+// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14-16"]' 'bar::sub::Trait'
+// @has - '//a[@href="../../src/foo/auxiliary/source-code-bar.rs.html#14-16"]' 'Trait'
+pub fn foo2<T: bar::sub::Trait, V: Trait>(t: &T, v: &V) {
+}
diff --git a/src/test/ui/asm/naked-functions-ffi.rs b/src/test/ui/asm/naked-functions-ffi.rs
new file mode 100644
index 00000000000..5b2a8ed3034
--- /dev/null
+++ b/src/test/ui/asm/naked-functions-ffi.rs
@@ -0,0 +1,12 @@
+// check-pass
+// only-x86_64
+#![feature(asm)]
+#![feature(naked_functions)]
+#![crate_type = "lib"]
+
+#[naked]
+pub extern "C" fn naked(p: char) -> u128 {
+    //~^ WARN uses type `char`
+    //~| WARN uses type `u128`
+    unsafe { asm!("", options(noreturn)); }
+}
diff --git a/src/test/ui/asm/naked-functions-ffi.stderr b/src/test/ui/asm/naked-functions-ffi.stderr
new file mode 100644
index 00000000000..a6772badeb6
--- /dev/null
+++ b/src/test/ui/asm/naked-functions-ffi.stderr
@@ -0,0 +1,20 @@
+warning: `extern` fn uses type `char`, which is not FFI-safe
+  --> $DIR/naked-functions-ffi.rs:8:28
+   |
+LL | pub extern "C" fn naked(p: char) -> u128 {
+   |                            ^^^^ not FFI-safe
+   |
+   = note: `#[warn(improper_ctypes_definitions)]` on by default
+   = help: consider using `u32` or `libc::wchar_t` instead
+   = note: the `char` type has no C equivalent
+
+warning: `extern` fn uses type `u128`, which is not FFI-safe
+  --> $DIR/naked-functions-ffi.rs:8:37
+   |
+LL | pub extern "C" fn naked(p: char) -> u128 {
+   |                                     ^^^^ not FFI-safe
+   |
+   = note: 128-bit integers don't currently have a known stable ABI
+
+warning: 2 warnings emitted
+
diff --git a/src/test/ui/asm/naked-functions-unused.rs b/src/test/ui/asm/naked-functions-unused.rs
new file mode 100644
index 00000000000..e1f2362bb6f
--- /dev/null
+++ b/src/test/ui/asm/naked-functions-unused.rs
@@ -0,0 +1,81 @@
+// only-x86_64
+#![deny(unused)]
+#![feature(asm)]
+#![feature(naked_functions)]
+#![crate_type = "lib"]
+
+pub trait Trait {
+    extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize;
+    extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize;
+}
+
+pub mod normal {
+    pub extern "sysv64" fn function(a: usize, b: usize) -> usize {
+        //~^ ERROR unused variable: `a`
+        //~| ERROR unused variable: `b`
+        unsafe { asm!("", options(noreturn)); }
+    }
+
+    pub struct Normal;
+
+    impl Normal {
+        pub extern "sysv64" fn associated(a: usize, b: usize) -> usize {
+            //~^ ERROR unused variable: `a`
+            //~| ERROR unused variable: `b`
+            unsafe { asm!("", options(noreturn)); }
+        }
+
+        pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize {
+            //~^ ERROR unused variable: `a`
+            //~| ERROR unused variable: `b`
+            unsafe { asm!("", options(noreturn)); }
+        }
+    }
+
+    impl super::Trait for Normal {
+        extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize {
+            //~^ ERROR unused variable: `a`
+            //~| ERROR unused variable: `b`
+            unsafe { asm!("", options(noreturn)); }
+        }
+
+        extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize {
+            //~^ ERROR unused variable: `a`
+            //~| ERROR unused variable: `b`
+            unsafe { asm!("", options(noreturn)); }
+        }
+    }
+}
+
+pub mod naked {
+    #[naked]
+    pub extern "sysv64" fn function(a: usize, b: usize) -> usize {
+        unsafe { asm!("", options(noreturn)); }
+    }
+
+    pub struct Naked;
+
+    impl Naked {
+        #[naked]
+        pub extern "sysv64" fn associated(a: usize, b: usize) -> usize {
+            unsafe { asm!("", options(noreturn)); }
+        }
+
+        #[naked]
+        pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize {
+            unsafe { asm!("", options(noreturn)); }
+        }
+    }
+
+    impl super::Trait for Naked {
+        #[naked]
+        extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize {
+            unsafe { asm!("", options(noreturn)); }
+        }
+
+        #[naked]
+        extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize {
+            unsafe { asm!("", options(noreturn)); }
+        }
+    }
+}
diff --git a/src/test/ui/asm/naked-functions-unused.stderr b/src/test/ui/asm/naked-functions-unused.stderr
new file mode 100644
index 00000000000..840353366b6
--- /dev/null
+++ b/src/test/ui/asm/naked-functions-unused.stderr
@@ -0,0 +1,69 @@
+error: unused variable: `a`
+  --> $DIR/naked-functions-unused.rs:13:37
+   |
+LL |     pub extern "sysv64" fn function(a: usize, b: usize) -> usize {
+   |                                     ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: the lint level is defined here
+  --> $DIR/naked-functions-unused.rs:2:9
+   |
+LL | #![deny(unused)]
+   |         ^^^^^^
+   = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]`
+
+error: unused variable: `b`
+  --> $DIR/naked-functions-unused.rs:13:47
+   |
+LL |     pub extern "sysv64" fn function(a: usize, b: usize) -> usize {
+   |                                               ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+  --> $DIR/naked-functions-unused.rs:22:43
+   |
+LL |         pub extern "sysv64" fn associated(a: usize, b: usize) -> usize {
+   |                                           ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+  --> $DIR/naked-functions-unused.rs:22:53
+   |
+LL |         pub extern "sysv64" fn associated(a: usize, b: usize) -> usize {
+   |                                                     ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+  --> $DIR/naked-functions-unused.rs:28:46
+   |
+LL |         pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize {
+   |                                              ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+  --> $DIR/naked-functions-unused.rs:28:56
+   |
+LL |         pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize {
+   |                                                        ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+  --> $DIR/naked-functions-unused.rs:36:45
+   |
+LL |         extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize {
+   |                                             ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+  --> $DIR/naked-functions-unused.rs:36:55
+   |
+LL |         extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize {
+   |                                                       ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+  --> $DIR/naked-functions-unused.rs:42:48
+   |
+LL |         extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize {
+   |                                                ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+  --> $DIR/naked-functions-unused.rs:42:58
+   |
+LL |         extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize {
+   |                                                          ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: aborting due to 10 previous errors
+
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/drop_impl.rs b/src/test/ui/const-generics/const_evaluatable_checked/drop_impl.rs
new file mode 100644
index 00000000000..41fb5d70afd
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/drop_impl.rs
@@ -0,0 +1,16 @@
+//check-pass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+struct Foo<const N: usize>
+where
+    [(); N + 1]: ;
+
+impl<const N: usize> Drop for Foo<N>
+where
+    [(); N + 1]: ,
+{
+    fn drop(&mut self) {}
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr
index 739e55e2943..3add0429d2d 100644
--- a/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr
+++ b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr
@@ -1,12 +1,12 @@
-error[E0107]: this function takes at most 1 generic argument but 2 generic arguments were supplied
+error[E0107]: this function takes 1 generic argument but 2 generic arguments were supplied
   --> $DIR/explicit-generic-args-for-impl.rs:6:5
    |
 LL |     foo::<str, String>("".to_string());
    |     ^^^        ------ help: remove this generic argument
    |     |
-   |     expected at most 1 generic argument
+   |     expected 1 generic argument
    |
-note: function defined here, with at most 1 generic parameter: `T`
+note: function defined here, with 1 generic parameter: `T`
   --> $DIR/explicit-generic-args-for-impl.rs:3:4
    |
 LL | fn foo<T: ?Sized>(_f: impl AsRef<T>) {}
diff --git a/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/issue-87718.rs b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/issue-87718.rs
new file mode 100644
index 00000000000..e2ee63821ae
--- /dev/null
+++ b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/issue-87718.rs
@@ -0,0 +1,9 @@
+// check-pass
+
+#![feature(explicit_generic_args_with_impl_trait)]
+
+fn f<T: ?Sized>(_: impl AsRef<T>, _: impl AsRef<T>) {}
+
+fn main() {
+    f::<[u8]>("a", b"a");
+}
diff --git a/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.rs b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.rs
new file mode 100644
index 00000000000..ffb0582fe8d
--- /dev/null
+++ b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.rs
@@ -0,0 +1,8 @@
+#![feature(explicit_generic_args_with_impl_trait)]
+
+fn f<T: ?Sized, U: ?Sized>(_: impl AsRef<T>, _: impl AsRef<U>) {}
+
+fn main() {
+    f::<[u8]>("a", b"a");
+    //~^ ERROR: this function takes 2 generic arguments but 1 generic argument was supplied
+}
diff --git a/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.stderr b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.stderr
new file mode 100644
index 00000000000..233b47445db
--- /dev/null
+++ b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/not-enough-args.stderr
@@ -0,0 +1,21 @@
+error[E0107]: this function takes 2 generic arguments but 1 generic argument was supplied
+  --> $DIR/not-enough-args.rs:6:5
+   |
+LL |     f::<[u8]>("a", b"a");
+   |     ^   ---- supplied 1 generic argument
+   |     |
+   |     expected 2 generic arguments
+   |
+note: function defined here, with 2 generic parameters: `T`, `U`
+  --> $DIR/not-enough-args.rs:3:4
+   |
+LL | fn f<T: ?Sized, U: ?Sized>(_: impl AsRef<T>, _: impl AsRef<U>) {}
+   |    ^ -          -
+help: add missing generic argument
+   |
+LL |     f::<[u8], U>("a", b"a");
+   |             ^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/thread-local-in-ctfe.stderr b/src/test/ui/thread-local-in-ctfe.stderr
index 9890597b7bd..fd967604624 100644
--- a/src/test/ui/thread-local-in-ctfe.stderr
+++ b/src/test/ui/thread-local-in-ctfe.stderr
@@ -30,3 +30,4 @@ LL |     A
 
 error: aborting due to 5 previous errors
 
+For more information about this error, try `rustc --explain E0625`.
diff --git a/src/test/ui/thread-local-static.stderr b/src/test/ui/thread-local-static.stderr
index 08bf593a5a7..712050a25fc 100644
--- a/src/test/ui/thread-local-static.stderr
+++ b/src/test/ui/thread-local-static.stderr
@@ -40,5 +40,5 @@ LL |     std::mem::swap(x, &mut STATIC_VAR_2)
 
 error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0013, E0133, E0658.
+Some errors have detailed explanations: E0013, E0133, E0625, E0658.
 For more information about an error, try `rustc --explain E0013`.