diff --git a/Cargo.lock b/Cargo.lock
index 9eba61f8d293b..73dc7f03236d1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -606,12 +606,22 @@ dependencies = [
  "atty",
  "bitflags",
  "indexmap",
+ "lazy_static",
  "os_str_bytes",
  "strsim 0.10.0",
  "termcolor",
  "textwrap 0.14.2",
 ]
 
+[[package]]
+name = "clap_complete"
+version = "3.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df6f3613c0a3cddfd78b41b10203eb322cb29b600cbdf808a7d3db95691b8e25"
+dependencies = [
+ "clap 3.1.1",
+]
+
 [[package]]
 name = "clippy"
 version = "0.1.62"
@@ -2240,14 +2250,15 @@ dependencies = [
 
 [[package]]
 name = "mdbook"
-version = "0.4.15"
+version = "0.4.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "241f10687eb3b4e0634b3b4e423f97c5f1efbd69dc9522e24a8b94583eeec3c6"
+checksum = "74612ae81a3e5ee509854049dfa4c7975ae033c06f5fc4735c7dfbe60ee2a39d"
 dependencies = [
  "ammonia",
  "anyhow",
  "chrono",
- "clap 2.34.0",
+ "clap 3.1.1",
+ "clap_complete",
  "elasticlunr-rs",
  "env_logger 0.7.1",
  "handlebars",
@@ -2911,7 +2922,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6"
 dependencies = [
  "bitflags",
- "getopts",
  "memchr",
  "unicase",
 ]
@@ -3129,9 +3139,9 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.5.4"
+version = "1.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
+checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
 dependencies = [
  "aho-corasick",
  "memchr",
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index c2247150d09c2..3c9bb81bedb1c 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -959,7 +959,7 @@ impl<'a> State<'a> {
                 self.word_space("=");
                 match term {
                     Term::Ty(ty) => self.print_type(ty),
-                    Term::Const(c) => self.print_expr_anon_const(c),
+                    Term::Const(c) => self.print_expr_anon_const(c, &[]),
                 }
             }
             ast::AssocConstraintKind::Bound { bounds } => self.print_type_bounds(":", &*bounds),
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index 6435f1b6141e3..9de4cbbee13f0 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -88,10 +88,21 @@ impl<'a> State<'a> {
         self.end();
     }
 
-    pub(super) fn print_expr_anon_const(&mut self, expr: &ast::AnonConst) {
+    pub(super) fn print_expr_anon_const(
+        &mut self,
+        expr: &ast::AnonConst,
+        attrs: &[ast::Attribute],
+    ) {
         self.ibox(INDENT_UNIT);
         self.word("const");
-        self.print_expr(&expr.value);
+        self.nbsp();
+        if let ast::ExprKind::Block(block, None) = &expr.value.kind {
+            self.cbox(0);
+            self.ibox(0);
+            self.print_block_with_attrs(block, attrs);
+        } else {
+            self.print_expr(&expr.value);
+        }
         self.end();
     }
 
@@ -275,7 +286,7 @@ impl<'a> State<'a> {
                 self.print_expr_vec(exprs);
             }
             ast::ExprKind::ConstBlock(ref anon_const) => {
-                self.print_expr_anon_const(anon_const);
+                self.print_expr_anon_const(anon_const, attrs);
             }
             ast::ExprKind::Repeat(ref element, ref count) => {
                 self.print_expr_repeat(element, count);
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 498b2f1b081b3..7cca6178ab257 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -188,6 +188,7 @@ pub(super) fn op_to_const<'tcx>(
     }
 }
 
+#[instrument(skip(tcx), level = "debug")]
 fn turn_into_const_value<'tcx>(
     tcx: TyCtxt<'tcx>,
     constant: ConstAlloc<'tcx>,
@@ -206,6 +207,7 @@ fn turn_into_const_value<'tcx>(
         !is_static || cid.promoted.is_some(),
         "the `eval_to_const_value_raw` query should not be used for statics, use `eval_to_allocation` instead"
     );
+
     // Turn this into a proper constant.
     op_to_const(&ecx, &mplace.into())
 }
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index 6fd7f707e7e5d..80270f825630f 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -3,12 +3,14 @@
 use std::convert::TryFrom;
 
 use rustc_hir::Mutability;
+use rustc_middle::ty::layout::HasTyCtxt;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_middle::{
     mir::{self, interpret::ConstAlloc},
     ty::ScalarInt,
 };
 use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
+use rustc_target::abi::VariantIdx;
 
 use crate::interpret::{
     intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MPlaceTy,
@@ -55,28 +57,48 @@ pub(crate) fn const_to_valtree<'tcx>(
     const_to_valtree_inner(&ecx, &place)
 }
 
-fn const_to_valtree_inner<'tcx>(
+#[instrument(skip(ecx), level = "debug")]
+fn branches<'tcx>(
     ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
     place: &MPlaceTy<'tcx>,
+    n: usize,
+    variant: Option<VariantIdx>,
 ) -> Option<ty::ValTree<'tcx>> {
-    let branches = |n, variant| {
-        let place = match variant {
-            Some(variant) => ecx.mplace_downcast(&place, variant).unwrap(),
-            None => *place,
-        };
-        let variant =
-            variant.map(|variant| Some(ty::ValTree::Leaf(ScalarInt::from(variant.as_u32()))));
-        let fields = (0..n).map(|i| {
-            let field = ecx.mplace_field(&place, i).unwrap();
-            const_to_valtree_inner(ecx, &field)
-        });
-        // For enums, we preped their variant index before the variant's fields so we can figure out
-        // the variant again when just seeing a valtree.
-        let branches = variant.into_iter().chain(fields);
-        Some(ty::ValTree::Branch(
-            ecx.tcx.arena.alloc_from_iter(branches.collect::<Option<Vec<_>>>()?),
-        ))
+    let place = match variant {
+        Some(variant) => ecx.mplace_downcast(&place, variant).unwrap(),
+        None => *place,
     };
+    let variant = variant.map(|variant| Some(ty::ValTree::Leaf(ScalarInt::from(variant.as_u32()))));
+    debug!(?place, ?variant);
+
+    let fields = (0..n).map(|i| {
+        let field = ecx.mplace_field(&place, i).unwrap();
+        const_to_valtree_inner(ecx, &field)
+    });
+    // For enums, we prepend their variant index before the variant's fields so we can figure out
+    // the variant again when just seeing a valtree.
+    let branches = variant.into_iter().chain(fields);
+    Some(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches.collect::<Option<Vec<_>>>()?)))
+}
+
+fn slice_branches<'tcx>(
+    ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
+    place: &MPlaceTy<'tcx>,
+) -> Option<ty::ValTree<'tcx>> {
+    let n = place.len(&ecx.tcx()).expect(&format!("expected to use len of place {:?}", place));
+    let branches = (0..n).map(|i| {
+        let place_elem = ecx.mplace_index(place, i).unwrap();
+        const_to_valtree_inner(ecx, &place_elem)
+    });
+
+    Some(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches.collect::<Option<Vec<_>>>()?)))
+}
+
+#[instrument(skip(ecx), level = "debug")]
+fn const_to_valtree_inner<'tcx>(
+    ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
+    place: &MPlaceTy<'tcx>,
+) -> Option<ty::ValTree<'tcx>> {
     match place.layout.ty.kind() {
         ty::FnDef(..) => Some(ty::ValTree::zst()),
         ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
@@ -90,19 +112,27 @@ fn const_to_valtree_inner<'tcx>(
         // Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
         // agree with runtime equality tests.
         ty::FnPtr(_) | ty::RawPtr(_) => None,
-        ty::Ref(..) => unimplemented!("need to use deref_const"),
 
+        ty::Ref(_, _, _)  => {
+            let derefd_place = ecx.deref_operand(&place.into()).unwrap_or_else(|e| bug!("couldn't deref {:?}, error: {:?}", place, e));
+            debug!(?derefd_place);
+
+            const_to_valtree_inner(ecx, &derefd_place)
+        }
+
+        ty::Str | ty::Slice(_) | ty::Array(_, _) => {
+            let valtree = slice_branches(ecx, place);
+            debug!(?valtree);
+
+            valtree
+        }
         // Trait objects are not allowed in type level constants, as we have no concept for
         // resolving their backing type, even if we can do that at const eval time. We may
         // hypothetically be able to allow `dyn StructuralEq` trait objects in the future,
         // but it is unclear if this is useful.
         ty::Dynamic(..) => None,
 
-        ty::Slice(_) | ty::Str => {
-            unimplemented!("need to find the backing data of the slice/str and recurse on that")
-        }
-        ty::Tuple(substs) => branches(substs.len(), None),
-        ty::Array(_, len) => branches(usize::try_from(len.eval_usize(ecx.tcx.tcx, ecx.param_env)).unwrap(), None),
+        ty::Tuple(substs) => branches(ecx, place, substs.len(), None),
 
         ty::Adt(def, _) => {
             if def.variants().is_empty() {
@@ -111,7 +141,7 @@ fn const_to_valtree_inner<'tcx>(
 
             let variant = ecx.read_discriminant(&place.into()).unwrap().1;
 
-            branches(def.variant(variant).fields.len(), def.is_enum().then_some(variant))
+            branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant))
         }
 
         ty::Never
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 8dc74035d61d0..31da4522a1fda 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -191,7 +191,7 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> {
     }
 
     #[inline]
-    pub(super) fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
+    pub(crate) fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
         if self.layout.is_unsized() {
             // We need to consult `meta` metadata
             match self.layout.ty.kind() {
diff --git a/compiler/rustc_data_structures/src/flock.rs b/compiler/rustc_data_structures/src/flock.rs
index 293ef4caac400..e395d8dbbbf8b 100644
--- a/compiler/rustc_data_structures/src/flock.rs
+++ b/compiler/rustc_data_structures/src/flock.rs
@@ -7,225 +7,20 @@
 #![allow(non_camel_case_types)]
 #![allow(nonstandard_style)]
 
-use std::fs::{File, OpenOptions};
-use std::io;
-use std::path::Path;
-
 cfg_if! {
-    // We use `flock` rather than `fcntl` on Linux, because WSL1 does not support
-    // `fcntl`-style advisory locks properly (rust-lang/rust#72157).
-    //
-    // For other Unix targets we still use `fcntl` because it's more portable than
-    // `flock`.
     if #[cfg(target_os = "linux")] {
-        use std::os::unix::prelude::*;
-
-        #[derive(Debug)]
-        pub struct Lock {
-            _file: File,
-        }
-
-        impl Lock {
-            pub fn new(p: &Path,
-                       wait: bool,
-                       create: bool,
-                       exclusive: bool)
-                       -> io::Result<Lock> {
-                let file = OpenOptions::new()
-                    .read(true)
-                    .write(true)
-                    .create(create)
-                    .mode(libc::S_IRWXU as u32)
-                    .open(p)?;
-
-                let mut operation = if exclusive {
-                    libc::LOCK_EX
-                } else {
-                    libc::LOCK_SH
-                };
-                if !wait {
-                    operation |= libc::LOCK_NB
-                }
-
-                let ret = unsafe { libc::flock(file.as_raw_fd(), operation) };
-                if ret == -1 {
-                    Err(io::Error::last_os_error())
-                } else {
-                    Ok(Lock { _file: file })
-                }
-            }
-
-            pub fn error_unsupported(err: &io::Error) -> bool {
-                matches!(err.raw_os_error(), Some(libc::ENOTSUP) | Some(libc::ENOSYS))
-            }
-        }
-
-        // Note that we don't need a Drop impl to execute `flock(fd, LOCK_UN)`. Lock acquired by
-        // `flock` is associated with the file descriptor and closing the file release it
-        // automatically.
+        mod linux;
+        use linux as imp;
     } else if #[cfg(unix)] {
-        use std::mem;
-        use std::os::unix::prelude::*;
-
-        #[derive(Debug)]
-        pub struct Lock {
-            file: File,
-        }
-
-        impl Lock {
-            pub fn new(p: &Path,
-                       wait: bool,
-                       create: bool,
-                       exclusive: bool)
-                       -> io::Result<Lock> {
-                let file = OpenOptions::new()
-                    .read(true)
-                    .write(true)
-                    .create(create)
-                    .mode(libc::S_IRWXU as u32)
-                    .open(p)?;
-
-                let lock_type = if exclusive {
-                    libc::F_WRLCK
-                } else {
-                    libc::F_RDLCK
-                };
-
-                let mut flock: libc::flock = unsafe { mem::zeroed() };
-                flock.l_type = lock_type as libc::c_short;
-                flock.l_whence = libc::SEEK_SET as libc::c_short;
-                flock.l_start = 0;
-                flock.l_len = 0;
-
-                let cmd = if wait { libc::F_SETLKW } else { libc::F_SETLK };
-                let ret = unsafe {
-                    libc::fcntl(file.as_raw_fd(), cmd, &flock)
-                };
-                if ret == -1 {
-                    Err(io::Error::last_os_error())
-                } else {
-                    Ok(Lock { file })
-                }
-            }
-
-            pub fn error_unsupported(err: &io::Error) -> bool {
-                matches!(err.raw_os_error(), Some(libc::ENOTSUP) | Some(libc::ENOSYS))
-            }
-        }
-
-        impl Drop for Lock {
-            fn drop(&mut self) {
-                let mut flock: libc::flock = unsafe { mem::zeroed() };
-                flock.l_type = libc::F_UNLCK as libc::c_short;
-                flock.l_whence = libc::SEEK_SET as libc::c_short;
-                flock.l_start = 0;
-                flock.l_len = 0;
-
-                unsafe {
-                    libc::fcntl(self.file.as_raw_fd(), libc::F_SETLK, &flock);
-                }
-            }
-        }
+        mod unix;
+        use unix as imp;
     } else if #[cfg(windows)] {
-        use std::mem;
-        use std::os::windows::prelude::*;
-
-        use winapi::shared::winerror::ERROR_INVALID_FUNCTION;
-        use winapi::um::minwinbase::{OVERLAPPED, LOCKFILE_FAIL_IMMEDIATELY, LOCKFILE_EXCLUSIVE_LOCK};
-        use winapi::um::fileapi::LockFileEx;
-        use winapi::um::winnt::{FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE};
-
-        #[derive(Debug)]
-        pub struct Lock {
-            _file: File,
-        }
-
-        impl Lock {
-            pub fn new(p: &Path,
-                       wait: bool,
-                       create: bool,
-                       exclusive: bool)
-                       -> io::Result<Lock> {
-                assert!(p.parent().unwrap().exists(),
-                    "Parent directory of lock-file must exist: {}",
-                    p.display());
-
-                let share_mode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
-
-                let mut open_options = OpenOptions::new();
-                open_options.read(true)
-                            .share_mode(share_mode);
-
-                if create {
-                    open_options.create(true)
-                                .write(true);
-                }
-
-                debug!("attempting to open lock file `{}`", p.display());
-                let file = match open_options.open(p) {
-                    Ok(file) => {
-                        debug!("lock file opened successfully");
-                        file
-                    }
-                    Err(err) => {
-                        debug!("error opening lock file: {}", err);
-                        return Err(err)
-                    }
-                };
-
-                let ret = unsafe {
-                    let mut overlapped: OVERLAPPED = mem::zeroed();
-
-                    let mut dwFlags = 0;
-                    if !wait {
-                        dwFlags |= LOCKFILE_FAIL_IMMEDIATELY;
-                    }
-
-                    if exclusive {
-                        dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
-                    }
-
-                    debug!("attempting to acquire lock on lock file `{}`",
-                           p.display());
-                    LockFileEx(file.as_raw_handle(),
-                               dwFlags,
-                               0,
-                               0xFFFF_FFFF,
-                               0xFFFF_FFFF,
-                               &mut overlapped)
-                };
-                if ret == 0 {
-                    let err = io::Error::last_os_error();
-                    debug!("failed acquiring file lock: {}", err);
-                    Err(err)
-                } else {
-                    debug!("successfully acquired lock");
-                    Ok(Lock { _file: file })
-                }
-            }
-
-            pub fn error_unsupported(err: &io::Error) -> bool {
-                err.raw_os_error() == Some(ERROR_INVALID_FUNCTION as i32)
-            }
-        }
-
-        // Note that we don't need a Drop impl on the Windows: The file is unlocked
-        // automatically when it's closed.
+        mod windows;
+        use windows as imp;
     } else {
-        #[derive(Debug)]
-        pub struct Lock(());
-
-        impl Lock {
-            pub fn new(_p: &Path, _wait: bool, _create: bool, _exclusive: bool)
-                -> io::Result<Lock>
-            {
-                let msg = "file locks not supported on this platform";
-                Err(io::Error::new(io::ErrorKind::Other, msg))
-            }
-
-            pub fn error_unsupported(_err: &io::Error) -> bool {
-                true
-            }
-        }
+        mod unsupported;
+        use unsupported as imp;
     }
 }
+
+pub use imp::Lock;
diff --git a/compiler/rustc_data_structures/src/flock/linux.rs b/compiler/rustc_data_structures/src/flock/linux.rs
new file mode 100644
index 0000000000000..bb3ecfbc370c0
--- /dev/null
+++ b/compiler/rustc_data_structures/src/flock/linux.rs
@@ -0,0 +1,40 @@
+//! We use `flock` rather than `fcntl` on Linux, because WSL1 does not support
+//! `fcntl`-style advisory locks properly (rust-lang/rust#72157). For other Unix
+//! targets we still use `fcntl` because it's more portable than `flock`.
+
+use std::fs::{File, OpenOptions};
+use std::io;
+use std::os::unix::prelude::*;
+use std::path::Path;
+
+#[derive(Debug)]
+pub struct Lock {
+    _file: File,
+}
+
+impl Lock {
+    pub fn new(p: &Path, wait: bool, create: bool, exclusive: bool) -> io::Result<Lock> {
+        let file = OpenOptions::new()
+            .read(true)
+            .write(true)
+            .create(create)
+            .mode(libc::S_IRWXU as u32)
+            .open(p)?;
+
+        let mut operation = if exclusive { libc::LOCK_EX } else { libc::LOCK_SH };
+        if !wait {
+            operation |= libc::LOCK_NB
+        }
+
+        let ret = unsafe { libc::flock(file.as_raw_fd(), operation) };
+        if ret == -1 { Err(io::Error::last_os_error()) } else { Ok(Lock { _file: file }) }
+    }
+
+    pub fn error_unsupported(err: &io::Error) -> bool {
+        matches!(err.raw_os_error(), Some(libc::ENOTSUP) | Some(libc::ENOSYS))
+    }
+}
+
+// Note that we don't need a Drop impl to execute `flock(fd, LOCK_UN)`. A lock acquired by
+// `flock` is associated with the file descriptor and closing the file releases it
+// automatically.
diff --git a/compiler/rustc_data_structures/src/flock/unix.rs b/compiler/rustc_data_structures/src/flock/unix.rs
new file mode 100644
index 0000000000000..4e5297d582e07
--- /dev/null
+++ b/compiler/rustc_data_structures/src/flock/unix.rs
@@ -0,0 +1,51 @@
+use std::fs::{File, OpenOptions};
+use std::io;
+use std::mem;
+use std::os::unix::prelude::*;
+use std::path::Path;
+
+#[derive(Debug)]
+pub struct Lock {
+    file: File,
+}
+
+impl Lock {
+    pub fn new(p: &Path, wait: bool, create: bool, exclusive: bool) -> io::Result<Lock> {
+        let file = OpenOptions::new()
+            .read(true)
+            .write(true)
+            .create(create)
+            .mode(libc::S_IRWXU as u32)
+            .open(p)?;
+
+        let lock_type = if exclusive { libc::F_WRLCK } else { libc::F_RDLCK };
+
+        let mut flock: libc::flock = unsafe { mem::zeroed() };
+        flock.l_type = lock_type as libc::c_short;
+        flock.l_whence = libc::SEEK_SET as libc::c_short;
+        flock.l_start = 0;
+        flock.l_len = 0;
+
+        let cmd = if wait { libc::F_SETLKW } else { libc::F_SETLK };
+        let ret = unsafe { libc::fcntl(file.as_raw_fd(), cmd, &flock) };
+        if ret == -1 { Err(io::Error::last_os_error()) } else { Ok(Lock { file }) }
+    }
+
+    pub fn error_unsupported(err: &io::Error) -> bool {
+        matches!(err.raw_os_error(), Some(libc::ENOTSUP) | Some(libc::ENOSYS))
+    }
+}
+
+impl Drop for Lock {
+    fn drop(&mut self) {
+        let mut flock: libc::flock = unsafe { mem::zeroed() };
+        flock.l_type = libc::F_UNLCK as libc::c_short;
+        flock.l_whence = libc::SEEK_SET as libc::c_short;
+        flock.l_start = 0;
+        flock.l_len = 0;
+
+        unsafe {
+            libc::fcntl(self.file.as_raw_fd(), libc::F_SETLK, &flock);
+        }
+    }
+}
diff --git a/compiler/rustc_data_structures/src/flock/unsupported.rs b/compiler/rustc_data_structures/src/flock/unsupported.rs
new file mode 100644
index 0000000000000..9245fca373dfc
--- /dev/null
+++ b/compiler/rustc_data_structures/src/flock/unsupported.rs
@@ -0,0 +1,16 @@
+use std::io;
+use std::path::Path;
+
+#[derive(Debug)]
+pub struct Lock(());
+
+impl Lock {
+    pub fn new(_p: &Path, _wait: bool, _create: bool, _exclusive: bool) -> io::Result<Lock> {
+        let msg = "file locks not supported on this platform";
+        Err(io::Error::new(io::ErrorKind::Other, msg))
+    }
+
+    pub fn error_unsupported(_err: &io::Error) -> bool {
+        true
+    }
+}
diff --git a/compiler/rustc_data_structures/src/flock/windows.rs b/compiler/rustc_data_structures/src/flock/windows.rs
new file mode 100644
index 0000000000000..43e6caaa18dcd
--- /dev/null
+++ b/compiler/rustc_data_structures/src/flock/windows.rs
@@ -0,0 +1,77 @@
+use std::fs::{File, OpenOptions};
+use std::io;
+use std::mem;
+use std::os::windows::prelude::*;
+use std::path::Path;
+
+use winapi::shared::winerror::ERROR_INVALID_FUNCTION;
+use winapi::um::fileapi::LockFileEx;
+use winapi::um::minwinbase::{LOCKFILE_EXCLUSIVE_LOCK, LOCKFILE_FAIL_IMMEDIATELY, OVERLAPPED};
+use winapi::um::winnt::{FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE};
+
+#[derive(Debug)]
+pub struct Lock {
+    _file: File,
+}
+
+impl Lock {
+    pub fn new(p: &Path, wait: bool, create: bool, exclusive: bool) -> io::Result<Lock> {
+        assert!(
+            p.parent().unwrap().exists(),
+            "Parent directory of lock-file must exist: {}",
+            p.display()
+        );
+
+        let share_mode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
+
+        let mut open_options = OpenOptions::new();
+        open_options.read(true).share_mode(share_mode);
+
+        if create {
+            open_options.create(true).write(true);
+        }
+
+        debug!("attempting to open lock file `{}`", p.display());
+        let file = match open_options.open(p) {
+            Ok(file) => {
+                debug!("lock file opened successfully");
+                file
+            }
+            Err(err) => {
+                debug!("error opening lock file: {}", err);
+                return Err(err);
+            }
+        };
+
+        let ret = unsafe {
+            let mut overlapped: OVERLAPPED = mem::zeroed();
+
+            let mut dwFlags = 0;
+            if !wait {
+                dwFlags |= LOCKFILE_FAIL_IMMEDIATELY;
+            }
+
+            if exclusive {
+                dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
+            }
+
+            debug!("attempting to acquire lock on lock file `{}`", p.display());
+            LockFileEx(file.as_raw_handle(), dwFlags, 0, 0xFFFF_FFFF, 0xFFFF_FFFF, &mut overlapped)
+        };
+        if ret == 0 {
+            let err = io::Error::last_os_error();
+            debug!("failed acquiring file lock: {}", err);
+            Err(err)
+        } else {
+            debug!("successfully acquired lock");
+            Ok(Lock { _file: file })
+        }
+    }
+
+    pub fn error_unsupported(err: &io::Error) -> bool {
+        err.raw_os_error() == Some(ERROR_INVALID_FUNCTION as i32)
+    }
+}
+
+// Note that we don't need a Drop impl on Windows: The file is unlocked
+// automatically when it's closed.
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 919b89396d678..6ec929f98950e 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -1659,49 +1659,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         self.tcx.const_eval_resolve(param_env_erased, unevaluated, span)
     }
 
-    /// If `typ` is a type variable of some kind, resolve it one level
-    /// (but do not resolve types found in the result). If `typ` is
-    /// not a type variable, just return it unmodified.
-    // FIXME(eddyb) inline into `ShallowResolver::visit_ty`.
-    fn shallow_resolve_ty(&self, typ: Ty<'tcx>) -> Ty<'tcx> {
-        match *typ.kind() {
-            ty::Infer(ty::TyVar(v)) => {
-                // Not entirely obvious: if `typ` is a type variable,
-                // it can be resolved to an int/float variable, which
-                // can then be recursively resolved, hence the
-                // recursion. Note though that we prevent type
-                // variables from unifying to other type variables
-                // directly (though they may be embedded
-                // structurally), and we prevent cycles in any case,
-                // so this recursion should always be of very limited
-                // depth.
-                //
-                // Note: if these two lines are combined into one we get
-                // dynamic borrow errors on `self.inner`.
-                let known = self.inner.borrow_mut().type_variables().probe(v).known();
-                known.map_or(typ, |t| self.shallow_resolve_ty(t))
-            }
-
-            ty::Infer(ty::IntVar(v)) => self
-                .inner
-                .borrow_mut()
-                .int_unification_table()
-                .probe_value(v)
-                .map(|v| v.to_type(self.tcx))
-                .unwrap_or(typ),
-
-            ty::Infer(ty::FloatVar(v)) => self
-                .inner
-                .borrow_mut()
-                .float_unification_table()
-                .probe_value(v)
-                .map(|v| v.to_type(self.tcx))
-                .unwrap_or(typ),
-
-            _ => typ,
-        }
-    }
-
     /// `ty_or_const_infer_var_changed` is equivalent to one of these two:
     ///   * `shallow_resolve(ty) != ty` (where `ty.kind = ty::Infer(_)`)
     ///   * `shallow_resolve(ct) != ct` (where `ct.kind = ty::ConstKind::Infer(_)`)
@@ -1831,8 +1788,46 @@ impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> {
         self.infcx.tcx
     }
 
+    /// If `ty` is a type variable of some kind, resolve it one level
+    /// (but do not resolve types found in the result). If `typ` is
+    /// not a type variable, just return it unmodified.
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.infcx.shallow_resolve_ty(ty)
+        match *ty.kind() {
+            ty::Infer(ty::TyVar(v)) => {
+                // Not entirely obvious: if `typ` is a type variable,
+                // it can be resolved to an int/float variable, which
+                // can then be recursively resolved, hence the
+                // recursion. Note though that we prevent type
+                // variables from unifying to other type variables
+                // directly (though they may be embedded
+                // structurally), and we prevent cycles in any case,
+                // so this recursion should always be of very limited
+                // depth.
+                //
+                // Note: if these two lines are combined into one we get
+                // dynamic borrow errors on `self.inner`.
+                let known = self.infcx.inner.borrow_mut().type_variables().probe(v).known();
+                known.map_or(ty, |t| self.fold_ty(t))
+            }
+
+            ty::Infer(ty::IntVar(v)) => self
+                .infcx
+                .inner
+                .borrow_mut()
+                .int_unification_table()
+                .probe_value(v)
+                .map_or(ty, |v| v.to_type(self.infcx.tcx)),
+
+            ty::Infer(ty::FloatVar(v)) => self
+                .infcx
+                .inner
+                .borrow_mut()
+                .float_unification_table()
+                .probe_value(v)
+                .map_or(ty, |v| v.to_type(self.infcx.tcx)),
+
+            _ => ty,
+        }
     }
 
     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs
index fae22c28628f8..195760c059081 100644
--- a/compiler/rustc_middle/src/ty/consts/valtree.rs
+++ b/compiler/rustc_middle/src/ty/consts/valtree.rs
@@ -1,5 +1,5 @@
 use super::ScalarInt;
-use rustc_macros::HashStable;
+use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 
 #[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)]
 #[derive(HashStable)]
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index f1956fb695bf7..cb6be8f412cf5 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -1125,13 +1125,13 @@ impl<'a> Parser<'a> {
             self.sess.gated_spans.gate(sym::inline_const, span);
         }
         self.eat_keyword(kw::Const);
-        let blk = self.parse_block()?;
+        let (attrs, blk) = self.parse_inner_attrs_and_block()?;
         let anon_const = AnonConst {
             id: DUMMY_NODE_ID,
             value: self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new()),
         };
         let blk_span = anon_const.value.span;
-        Ok(self.mk_expr(span.to(blk_span), ExprKind::ConstBlock(anon_const), AttrVec::new()))
+        Ok(self.mk_expr(span.to(blk_span), ExprKind::ConstBlock(anon_const), AttrVec::from(attrs)))
     }
 
     /// Parses mutability (`mut` or nothing).
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index c45326e1e6e6c..a9444972130a8 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -80,6 +80,7 @@ impl CheckAttrVisitor<'_> {
                     self.check_rustc_must_implement_one_of(attr, span, target)
                 }
                 sym::target_feature => self.check_target_feature(hir_id, attr, span, target),
+                sym::thread_local => self.check_thread_local(attr, span, target),
                 sym::track_caller => {
                     self.check_track_caller(hir_id, attr.span, attrs, span, target)
                 }
@@ -523,6 +524,21 @@ impl CheckAttrVisitor<'_> {
         }
     }
 
+    /// Checks if the `#[thread_local]` attribute on `item` is valid. Returns `true` if valid.
+    fn check_thread_local(&self, attr: &Attribute, span: Span, target: Target) -> bool {
+        match target {
+            Target::ForeignStatic | Target::Static => true,
+            _ => {
+                self.tcx
+                    .sess
+                    .struct_span_err(attr.span, "attribute should be applied to a static")
+                    .span_label(span, "not a static")
+                    .emit();
+                false
+            }
+        }
+    }
+
     fn doc_attr_str_error(&self, meta: &NestedMetaItem, attr_name: &str) {
         self.tcx
             .sess
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 62f3527525e0e..fffd94992093b 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -116,7 +116,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
             name: None,
             attrs: Default::default(),
             visibility: Inherited,
-            def_id: ItemId::Auto { trait_: trait_def_id, for_: item_def_id },
+            item_id: ItemId::Auto { trait_: trait_def_id, for_: item_def_id },
             kind: box ImplItem(Impl {
                 unsafety: hir::Unsafety::Normal,
                 generics: new_generics,
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 6f4b87750ff85..f0d87f7ce4cd5 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -105,7 +105,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                         name: None,
                         attrs: Default::default(),
                         visibility: Inherited,
-                        def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
+                        item_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
                         kind: box ImplItem(Impl {
                             unsafety: hir::Unsafety::Normal,
                             generics: clean_ty_generics(
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 33db6583125ef..261eb39bf723d 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -534,7 +534,7 @@ fn build_module(
                 items.push(clean::Item {
                     name: None,
                     attrs: box clean::Attributes::default(),
-                    def_id: ItemId::Primitive(prim_ty, did.krate),
+                    item_id: ItemId::Primitive(prim_ty, did.krate),
                     visibility: clean::Public,
                     kind: box clean::ImportItem(clean::Import::new_simple(
                         item.ident.name,
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index a6763d2827cec..21016afbf5f99 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2009,7 +2009,7 @@ fn clean_extern_crate(
     vec![Item {
         name: Some(name),
         attrs: box attrs.clean(cx),
-        def_id: crate_def_id.into(),
+        item_id: crate_def_id.into(),
         visibility: ty_vis.clean(cx),
         kind: box ExternCrateItem { src: orig_name },
         cfg: attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index d2abfc35b932c..4b473df155f58 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -366,7 +366,7 @@ crate struct Item {
     /// Information about this item that is specific to what kind of item it is.
     /// E.g., struct vs enum vs function.
     crate kind: Box<ItemKind>,
-    crate def_id: ItemId,
+    crate item_id: ItemId,
 
     crate cfg: Option<Arc<Cfg>>,
 }
@@ -380,7 +380,7 @@ impl fmt::Debug for Item {
         let mut fmt = f.debug_struct("Item");
         fmt.field("name", &self.name)
             .field("visibility", &self.visibility)
-            .field("def_id", &self.def_id);
+            .field("item_id", &self.item_id);
         // allow printing the full item if someone really wants to
         if alternate {
             fmt.field("attrs", &self.attrs).field("kind", &self.kind).field("cfg", &self.cfg);
@@ -408,19 +408,19 @@ crate fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
 
 impl Item {
     crate fn stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<Stability> {
-        self.def_id.as_def_id().and_then(|did| tcx.lookup_stability(did))
+        self.item_id.as_def_id().and_then(|did| tcx.lookup_stability(did))
     }
 
     crate fn const_stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<ConstStability> {
-        self.def_id.as_def_id().and_then(|did| tcx.lookup_const_stability(did))
+        self.item_id.as_def_id().and_then(|did| tcx.lookup_const_stability(did))
     }
 
     crate fn deprecation(&self, tcx: TyCtxt<'_>) -> Option<Deprecation> {
-        self.def_id.as_def_id().and_then(|did| tcx.lookup_deprecation(did))
+        self.item_id.as_def_id().and_then(|did| tcx.lookup_deprecation(did))
     }
 
     crate fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool {
-        self.def_id.as_def_id().map(|did| tcx.get_attrs(did).inner_docs()).unwrap_or(false)
+        self.item_id.as_def_id().map(|did| tcx.get_attrs(did).inner_docs()).unwrap_or(false)
     }
 
     crate fn span(&self, tcx: TyCtxt<'_>) -> Span {
@@ -432,14 +432,14 @@ impl Item {
             ItemKind::ModuleItem(Module { span, .. }) => *span,
             ItemKind::ImplItem(Impl { kind: ImplKind::Auto, .. }) => Span::dummy(),
             ItemKind::ImplItem(Impl { kind: ImplKind::Blanket(_), .. }) => {
-                if let ItemId::Blanket { impl_id, .. } = self.def_id {
+                if let ItemId::Blanket { impl_id, .. } = self.item_id {
                     rustc_span(impl_id, tcx)
                 } else {
                     panic!("blanket impl item has non-blanket ID")
                 }
             }
             _ => {
-                self.def_id.as_def_id().map(|did| rustc_span(did, tcx)).unwrap_or_else(Span::dummy)
+                self.item_id.as_def_id().map(|did| rustc_span(did, tcx)).unwrap_or_else(Span::dummy)
             }
         }
     }
@@ -503,7 +503,7 @@ impl Item {
             cx.tcx.visibility(def_id).clean(cx)
         };
 
-        Item { def_id: def_id.into(), kind: box kind, name, attrs, visibility, cfg }
+        Item { item_id: def_id.into(), kind: box kind, name, attrs, visibility, cfg }
     }
 
     /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
@@ -517,7 +517,7 @@ impl Item {
 
         cx.cache()
             .intra_doc_links
-            .get(&self.def_id)
+            .get(&self.item_id)
             .map_or(&[][..], |v| v.as_slice())
             .iter()
             .filter_map(|ItemLink { link: s, link_text, did, ref fragment }| {
@@ -547,7 +547,7 @@ impl Item {
     crate fn link_names(&self, cache: &Cache) -> Vec<RenderedLink> {
         cache
             .intra_doc_links
-            .get(&self.def_id)
+            .get(&self.item_id)
             .map_or(&[][..], |v| v.as_slice())
             .iter()
             .map(|ItemLink { link: s, link_text, .. }| RenderedLink {
@@ -559,7 +559,7 @@ impl Item {
     }
 
     crate fn is_crate(&self) -> bool {
-        self.is_mod() && self.def_id.as_def_id().map_or(false, |did| did.index == CRATE_DEF_INDEX)
+        self.is_mod() && self.item_id.as_def_id().map_or(false, |did| did.index == CRATE_DEF_INDEX)
     }
     crate fn is_mod(&self) -> bool {
         self.type_() == ItemType::Module
@@ -695,7 +695,7 @@ impl Item {
         }
         let header = match *self.kind {
             ItemKind::ForeignFunctionItem(_) => {
-                let abi = tcx.fn_sig(self.def_id.as_def_id().unwrap()).abi();
+                let abi = tcx.fn_sig(self.item_id.as_def_id().unwrap()).abi();
                 hir::FnHeader {
                     unsafety: if abi == Abi::RustIntrinsic {
                         intrinsic_operation_unsafety(self.name.unwrap())
@@ -708,11 +708,11 @@ impl Item {
                 }
             }
             ItemKind::FunctionItem(_) | ItemKind::MethodItem(_, _) => {
-                let def_id = self.def_id.as_def_id().unwrap();
+                let def_id = self.item_id.as_def_id().unwrap();
                 build_fn_header(def_id, tcx, tcx.asyncness(def_id))
             }
             ItemKind::TyMethodItem(_) => {
-                build_fn_header(self.def_id.as_def_id().unwrap(), tcx, hir::IsAsync::NotAsync)
+                build_fn_header(self.item_id.as_def_id().unwrap(), tcx, hir::IsAsync::NotAsync)
             }
             _ => return None,
         };
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index fe6d680991f80..abfc5b80a3ef0 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -44,9 +44,9 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate {
                 // `#[doc(masked)]` to the injected `extern crate` because it's unstable.
                 if it.is_extern_crate()
                     && (it.attrs.has_doc_flag(sym::masked)
-                        || cx.tcx.is_compiler_builtins(it.def_id.krate()))
+                        || cx.tcx.is_compiler_builtins(it.item_id.krate()))
                 {
-                    cx.cache.masked_crates.insert(it.def_id.krate());
+                    cx.cache.masked_crates.insert(it.item_id.krate());
                 }
             }
         }
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 81c11dc30cb58..b9e20c41b681f 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -113,8 +113,8 @@ impl<'tcx> DocContext<'tcx> {
 
     /// Like `hir().local_def_id_to_hir_id()`, but skips calling it on fake DefIds.
     /// (This avoids a slice-index-out-of-bounds panic.)
-    crate fn as_local_hir_id(tcx: TyCtxt<'_>, def_id: ItemId) -> Option<HirId> {
-        match def_id {
+    crate fn as_local_hir_id(tcx: TyCtxt<'_>, item_id: ItemId) -> Option<HirId> {
+        match item_id {
             ItemId::DefId(real_id) => {
                 real_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
             }
@@ -390,7 +390,7 @@ crate fn run_global_ctxt(
         );
         tcx.struct_lint_node(
             crate::lint::MISSING_CRATE_LEVEL_DOCS,
-            DocContext::as_local_hir_id(tcx, krate.module.def_id).unwrap(),
+            DocContext::as_local_hir_id(tcx, krate.module.item_id).unwrap(),
             |lint| {
                 let mut diag =
                     lint.build("no documentation found for this crate's top-level module");
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 663e18fe9129f..e138e434c4e04 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -186,8 +186,8 @@ impl Cache {
 
 impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
     fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
-        if item.def_id.is_local() {
-            debug!("folding {} \"{:?}\", id {:?}", item.type_(), item.name, item.def_id);
+        if item.item_id.is_local() {
+            debug!("folding {} \"{:?}\", id {:?}", item.type_(), item.name, item.item_id);
         }
 
         // If this is a stripped module,
@@ -202,7 +202,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
         // If the impl is from a masked crate or references something from a
         // masked crate then remove it completely.
         if let clean::ImplItem(ref i) = *item.kind {
-            if self.cache.masked_crates.contains(&item.def_id.krate())
+            if self.cache.masked_crates.contains(&item.item_id.krate())
                 || i.trait_
                     .as_ref()
                     .map_or(false, |t| self.cache.masked_crates.contains(&t.def_id().krate))
@@ -217,7 +217,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
         // Propagate a trait method's documentation to all implementors of the
         // trait.
         if let clean::TraitItem(ref t) = *item.kind {
-            self.cache.traits.entry(item.def_id.expect_def_id()).or_insert_with(|| {
+            self.cache.traits.entry(item.item_id.expect_def_id()).or_insert_with(|| {
                 clean::TraitWithExtraInfo {
                     trait_: t.clone(),
                     is_notable: item.attrs.has_doc_flag(sym::notable_trait),
@@ -293,7 +293,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                     // A crate has a module at its root, containing all items,
                     // which should not be indexed. The crate-item itself is
                     // inserted later on when serializing the search-index.
-                    if item.def_id.index().map_or(false, |idx| idx != CRATE_DEF_INDEX) {
+                    if item.item_id.index().map_or(false, |idx| idx != CRATE_DEF_INDEX) {
                         let desc = item.doc_value().map_or_else(String::new, |x| {
                             short_markdown_summary(x.as_str(), &item.link_names(self.cache))
                         });
@@ -351,11 +351,11 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                     // `public_items` map, so we can skip inserting into the
                     // paths map if there was already an entry present and we're
                     // not a public item.
-                    if !self.cache.paths.contains_key(&item.def_id.expect_def_id())
-                        || self.cache.access_levels.is_public(item.def_id.expect_def_id())
+                    if !self.cache.paths.contains_key(&item.item_id.expect_def_id())
+                        || self.cache.access_levels.is_public(item.item_id.expect_def_id())
                     {
                         self.cache.paths.insert(
-                            item.def_id.expect_def_id(),
+                            item.item_id.expect_def_id(),
                             (self.cache.stack.clone(), item.type_()),
                         );
                     }
@@ -364,7 +364,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
             clean::PrimitiveItem(..) => {
                 self.cache
                     .paths
-                    .insert(item.def_id.expect_def_id(), (self.cache.stack.clone(), item.type_()));
+                    .insert(item.item_id.expect_def_id(), (self.cache.stack.clone(), item.type_()));
             }
 
             clean::ExternCrateItem { .. }
@@ -396,7 +396,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
             | clean::StructItem(..)
             | clean::UnionItem(..)
             | clean::VariantItem(..) => {
-                self.cache.parent_stack.push(item.def_id.expect_def_id());
+                self.cache.parent_stack.push(item.item_id.expect_def_id());
                 self.cache.parent_is_trait_impl = false;
                 true
             }
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 90123655758cc..8e643107353dd 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -222,7 +222,7 @@ impl<'tcx> Context<'tcx> {
                 &self.shared.style_files,
             )
         } else {
-            if let Some(&(ref names, ty)) = self.cache().paths.get(&it.def_id.expect_def_id()) {
+            if let Some(&(ref names, ty)) = self.cache().paths.get(&it.item_id.expect_def_id()) {
                 if self.current.len() + 1 != names.len()
                     || self.current.iter().zip(names.iter()).any(|(a, b)| a != b)
                 {
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index a4cc42e2a0185..7a4289b8e60e9 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -830,7 +830,7 @@ fn assoc_const(
         w,
         "{extra}{vis}const <a{href} class=\"constant\">{name}</a>: {ty}",
         extra = extra,
-        vis = it.visibility.print_with_space(it.def_id, cx),
+        vis = it.visibility.print_with_space(it.item_id, cx),
         href = assoc_href_attr(it, link, cx),
         name = it.name.as_ref().unwrap(),
         ty = ty.print(cx),
@@ -884,7 +884,7 @@ fn assoc_method(
 ) {
     let header = meth.fn_header(cx.tcx()).expect("Trying to get header from a non-function item");
     let name = meth.name.as_ref().unwrap();
-    let vis = meth.visibility.print_with_space(meth.def_id, cx).to_string();
+    let vis = meth.visibility.print_with_space(meth.item_id, cx).to_string();
     // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
     // this condition.
     let constness = match render_mode {
@@ -2060,7 +2060,7 @@ fn small_url_encode(s: String) -> String {
 }
 
 fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
-    let did = it.def_id.expect_def_id();
+    let did = it.item_id.expect_def_id();
     let cache = cx.cache();
 
     if let Some(v) = cache.impls.get(&did) {
@@ -2412,7 +2412,7 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean
     );
 
     let cache = cx.cache();
-    if let Some(implementors) = cache.implementors.get(&it.def_id.expect_def_id()) {
+    if let Some(implementors) = cache.implementors.get(&it.item_id.expect_def_id()) {
         let mut res = implementors
             .iter()
             .filter(|i| {
@@ -2761,7 +2761,7 @@ const NUM_VISIBLE_LINES: usize = 10;
 /// Generates the HTML for example call locations generated via the --scrape-examples flag.
 fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item) {
     let tcx = cx.tcx();
-    let def_id = item.def_id.expect_def_id();
+    let def_id = item.item_id.expect_def_id();
     let key = tcx.def_path_hash(def_id);
     let Some(call_locations) = cx.shared.call_locations.get(&key) else { return };
 
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 1ed5c662c41cc..f1915920b6d05 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -264,7 +264,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
     // (which is the position in the vector).
     indices.dedup_by_key(|i| {
         (
-            items[*i].def_id,
+            items[*i].item_id,
             if items[*i].name.is_some() { Some(full_path(cx, &items[*i])) } else { None },
             items[*i].type_(),
             if items[*i].is_import() { *i } else { 0 },
@@ -306,15 +306,15 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
                     Some(src) => write!(
                         w,
                         "<div class=\"item-left\"><code>{}extern crate {} as {};",
-                        myitem.visibility.print_with_space(myitem.def_id, cx),
-                        anchor(myitem.def_id.expect_def_id(), src, cx),
+                        myitem.visibility.print_with_space(myitem.item_id, cx),
+                        anchor(myitem.item_id.expect_def_id(), src, cx),
                         myitem.name.unwrap(),
                     ),
                     None => write!(
                         w,
                         "<div class=\"item-left\"><code>{}extern crate {};",
-                        myitem.visibility.print_with_space(myitem.def_id, cx),
-                        anchor(myitem.def_id.expect_def_id(), myitem.name.unwrap(), cx),
+                        myitem.visibility.print_with_space(myitem.item_id, cx),
+                        anchor(myitem.item_id.expect_def_id(), myitem.name.unwrap(), cx),
                     ),
                 }
                 w.write_str("</code></div>");
@@ -328,7 +328,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
 
                     // Just need an item with the correct def_id and attrs
                     let import_item = clean::Item {
-                        def_id: import_def_id.into(),
+                        item_id: import_def_id.into(),
                         attrs: import_attrs,
                         cfg: ast_attrs.cfg(cx.tcx(), &cx.cache().hidden_cfg),
                         ..myitem.clone()
@@ -352,7 +352,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
                      <div class=\"item-right docblock-short\">{stab_tags}</div>",
                     stab = stab.unwrap_or_default(),
                     add = add,
-                    vis = myitem.visibility.print_with_space(myitem.def_id, cx),
+                    vis = myitem.visibility.print_with_space(myitem.item_id, cx),
                     imp = import.print(cx),
                     stab_tags = stab_tags.unwrap_or_default(),
                 );
@@ -468,7 +468,7 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::
     let unsafety = header.unsafety.print_with_space();
     let abi = print_abi_with_space(header.abi).to_string();
     let asyncness = header.asyncness.print_with_space();
-    let visibility = it.visibility.print_with_space(it.def_id, cx).to_string();
+    let visibility = it.visibility.print_with_space(it.item_id, cx).to_string();
     let name = it.name.unwrap();
 
     let generics_len = format!("{:#}", f.generics.print(cx)).len();
@@ -524,7 +524,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
             write!(
                 w,
                 "{}{}{}trait {}{}{}",
-                it.visibility.print_with_space(it.def_id, cx),
+                it.visibility.print_with_space(it.item_id, cx),
                 t.unsafety.print_with_space(),
                 if t.is_auto { "auto " } else { "" },
                 it.name.unwrap(),
@@ -787,10 +787,10 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
     }
 
     // If there are methods directly on this trait object, render them here.
-    render_assoc_items(w, cx, it, it.def_id.expect_def_id(), AssocItemRender::All);
+    render_assoc_items(w, cx, it, it.item_id.expect_def_id(), AssocItemRender::All);
 
     let cache = cx.cache();
-    if let Some(implementors) = cache.implementors.get(&it.def_id.expect_def_id()) {
+    if let Some(implementors) = cache.implementors.get(&it.item_id.expect_def_id()) {
         // The DefId is for the first Type found with that name. The bool is
         // if any Types with the same name but different DefId have been found.
         let mut implementor_dups: FxHashMap<Symbol, (DefId, bool)> = FxHashMap::default();
@@ -827,7 +827,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
             for implementor in foreign {
                 let provided_methods = implementor.inner_impl().provided_trait_methods(cx.tcx());
                 let assoc_link =
-                    AssocItemLink::GotoSource(implementor.impl_item.def_id, &provided_methods);
+                    AssocItemLink::GotoSource(implementor.impl_item.item_id, &provided_methods);
                 render_impl(
                     w,
                     cx,
@@ -902,10 +902,10 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
         .take(cx.current.len())
         .chain(std::iter::once("implementors"))
         .collect();
-    if it.def_id.is_local() {
+    if it.item_id.is_local() {
         js_src_path.extend(cx.current.iter().copied());
     } else {
-        let (ref path, _) = cache.external_paths[&it.def_id.expect_def_id()];
+        let (ref path, _) = cache.external_paths[&it.item_id.expect_def_id()];
         js_src_path.extend(path[..path.len() - 1].iter().copied());
     }
     js_src_path.push_fmt(format_args!("{}.{}.js", it.type_(), it.name.unwrap()));
@@ -937,7 +937,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clea
     // won't be visible anywhere in the docs. It would be nice to also show
     // associated items from the aliased type (see discussion in #32077), but
     // we need #14072 to make sense of the generics.
-    render_assoc_items(w, cx, it, it.def_id.expect_def_id(), AssocItemRender::All)
+    render_assoc_items(w, cx, it, it.item_id.expect_def_id(), AssocItemRender::All)
 }
 
 fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::OpaqueTy) {
@@ -961,14 +961,14 @@ fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean:
     // won't be visible anywhere in the docs. It would be nice to also show
     // associated items from the aliased type (see discussion in #32077), but
     // we need #14072 to make sense of the generics.
-    render_assoc_items(w, cx, it, it.def_id.expect_def_id(), AssocItemRender::All)
+    render_assoc_items(w, cx, it, it.item_id.expect_def_id(), AssocItemRender::All)
 }
 
 fn item_typedef(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) {
     fn write_content(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) {
         wrap_item(w, "typedef", |w| {
             render_attributes_in_pre(w, it, "");
-            write!(w, "{}", it.visibility.print_with_space(it.def_id, cx));
+            write!(w, "{}", it.visibility.print_with_space(it.item_id, cx));
             write!(
                 w,
                 "type {}{}{where_clause} = {type_};",
@@ -984,7 +984,7 @@ fn item_typedef(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::T
 
     document(w, cx, it, None, HeadingOffset::H2);
 
-    let def_id = it.def_id.expect_def_id();
+    let def_id = it.item_id.expect_def_id();
     // Render any items associated directly to this alias, as otherwise they
     // won't be visible anywhere in the docs. It would be nice to also show
     // associated items from the aliased type (see discussion in #32077), but
@@ -1037,7 +1037,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
             document(w, cx, field, Some(it), HeadingOffset::H3);
         }
     }
-    let def_id = it.def_id.expect_def_id();
+    let def_id = it.item_id.expect_def_id();
     render_assoc_items(w, cx, it, def_id, AssocItemRender::All);
     document_type_layout(w, cx, def_id);
 }
@@ -1062,7 +1062,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
             write!(
                 w,
                 "{}enum {}{}{}",
-                it.visibility.print_with_space(it.def_id, cx),
+                it.visibility.print_with_space(it.item_id, cx),
                 it.name.unwrap(),
                 e.generics.print(cx),
                 print_where_clause(&e.generics, cx, 0, true),
@@ -1197,7 +1197,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
             document(w, cx, variant, Some(it), HeadingOffset::H4);
         }
     }
-    let def_id = it.def_id.expect_def_id();
+    let def_id = it.item_id.expect_def_id();
     render_assoc_items(w, cx, it, def_id, AssocItemRender::All);
     document_type_layout(w, cx, def_id);
 }
@@ -1253,7 +1253,7 @@ fn item_proc_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, m: &clean
 
 fn item_primitive(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
     document(w, cx, it, None, HeadingOffset::H2);
-    render_assoc_items(w, cx, it, it.def_id.expect_def_id(), AssocItemRender::All)
+    render_assoc_items(w, cx, it, it.item_id.expect_def_id(), AssocItemRender::All)
 }
 
 fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean::Constant) {
@@ -1264,7 +1264,7 @@ fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean::
             write!(
                 w,
                 "{vis}const {name}: {typ}",
-                vis = it.visibility.print_with_space(it.def_id, cx),
+                vis = it.visibility.print_with_space(it.item_id, cx),
                 name = it.name.unwrap(),
                 typ = c.type_.print(cx),
             );
@@ -1344,7 +1344,7 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
             }
         }
     }
-    let def_id = it.def_id.expect_def_id();
+    let def_id = it.item_id.expect_def_id();
     render_assoc_items(w, cx, it, def_id, AssocItemRender::All);
     document_type_layout(w, cx, def_id);
 }
@@ -1356,7 +1356,7 @@ fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
             write!(
                 w,
                 "{vis}static {mutability}{name}: {typ}",
-                vis = it.visibility.print_with_space(it.def_id, cx),
+                vis = it.visibility.print_with_space(it.item_id, cx),
                 mutability = s.mutability.print_with_space(),
                 name = it.name.unwrap(),
                 typ = s.type_.print(cx)
@@ -1374,7 +1374,7 @@ fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
             write!(
                 w,
                 "    {}type {};\n}}",
-                it.visibility.print_with_space(it.def_id, cx),
+                it.visibility.print_with_space(it.item_id, cx),
                 it.name.unwrap(),
             );
         });
@@ -1382,7 +1382,7 @@ fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
 
     document(w, cx, it, None, HeadingOffset::H2);
 
-    render_assoc_items(w, cx, it, it.def_id.expect_def_id(), AssocItemRender::All)
+    render_assoc_items(w, cx, it, it.item_id.expect_def_id(), AssocItemRender::All)
 }
 
 fn item_keyword(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
@@ -1543,7 +1543,7 @@ fn render_union(
     tab: &str,
     cx: &Context<'_>,
 ) {
-    write!(w, "{}union {}", it.visibility.print_with_space(it.def_id, cx), it.name.unwrap());
+    write!(w, "{}union {}", it.visibility.print_with_space(it.item_id, cx), it.name.unwrap());
     if let Some(g) = g {
         write!(w, "{}", g.print(cx));
         write!(w, "{}", print_where_clause(g, cx, 0, true));
@@ -1562,7 +1562,7 @@ fn render_union(
             write!(
                 w,
                 "    {}{}: {},\n{}",
-                field.visibility.print_with_space(field.def_id, cx),
+                field.visibility.print_with_space(field.item_id, cx),
                 field.name.unwrap(),
                 ty.print(cx),
                 tab
@@ -1592,7 +1592,7 @@ fn render_struct(
     write!(
         w,
         "{}{}{}",
-        it.visibility.print_with_space(it.def_id, cx),
+        it.visibility.print_with_space(it.item_id, cx),
         if structhead { "struct " } else { "" },
         it.name.unwrap()
     );
@@ -1618,7 +1618,7 @@ fn render_struct(
                         w,
                         "\n{}    {}{}: {},",
                         tab,
-                        field.visibility.print_with_space(field.def_id, cx),
+                        field.visibility.print_with_space(field.item_id, cx),
                         field.name.unwrap(),
                         ty.print(cx),
                     );
@@ -1650,7 +1650,7 @@ fn render_struct(
                         write!(
                             w,
                             "{}{}",
-                            field.visibility.print_with_space(field.def_id, cx),
+                            field.visibility.print_with_space(field.item_id, cx),
                             ty.print(cx),
                         )
                     }
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index 3fa16c6c3b880..371d0e8408754 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -535,7 +535,7 @@ pub(super) fn write_shared(
                 //
                 // If the implementation is from another crate then that crate
                 // should add it.
-                if imp.impl_item.def_id.krate() == did.krate || !imp.impl_item.def_id.is_local() {
+                if imp.impl_item.item_id.krate() == did.krate || !imp.impl_item.item_id.is_local() {
                     None
                 } else {
                     Some(Implementor {
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index a9a6a31fccd0d..0b5fb48059579 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -27,7 +27,7 @@ impl JsonRenderer<'_> {
         let links = self
             .cache
             .intra_doc_links
-            .get(&item.def_id)
+            .get(&item.item_id)
             .into_iter()
             .flatten()
             .map(|clean::ItemLink { link, did, .. }| (link.clone(), from_item_id((*did).into())))
@@ -40,14 +40,14 @@ impl JsonRenderer<'_> {
             .map(rustc_ast_pretty::pprust::attribute_to_string)
             .collect();
         let span = item.span(self.tcx);
-        let clean::Item { name, attrs: _, kind: _, visibility, def_id, cfg: _ } = item;
+        let clean::Item { name, attrs: _, kind: _, visibility, item_id, cfg: _ } = item;
         let inner = match *item.kind {
             clean::StrippedItem(_) => return None,
             _ => from_clean_item(item, self.tcx),
         };
         Some(Item {
-            id: from_item_id(def_id),
-            crate_id: def_id.krate().as_u32(),
+            id: from_item_id(item_id),
+            crate_id: item_id.krate().as_u32(),
             name: name.map(|sym| sym.to_string()),
             span: self.convert_span(span),
             visibility: self.convert_visibility(visibility),
@@ -174,7 +174,7 @@ impl FromWithTcx<clean::TypeBindingKind> for TypeBindingKind {
     }
 }
 
-crate fn from_item_id(did: ItemId) -> Id {
+crate fn from_item_id(item_id: ItemId) -> Id {
     struct DisplayDefId(DefId);
 
     impl fmt::Display for DisplayDefId {
@@ -183,7 +183,7 @@ crate fn from_item_id(did: ItemId) -> Id {
         }
     }
 
-    match did {
+    match item_id {
         ItemId::DefId(did) => Id(format!("{}", DisplayDefId(did))),
         ItemId::Blanket { for_, impl_id } => {
             Id(format!("b:{}-{}", DisplayDefId(impl_id), DisplayDefId(for_)))
@@ -732,5 +732,5 @@ impl FromWithTcx<ItemType> for ItemKind {
 }
 
 fn ids(items: impl IntoIterator<Item = clean::Item>) -> Vec<Id> {
-    items.into_iter().filter(|x| !x.is_stripped()).map(|i| from_item_id(i.def_id)).collect()
+    items.into_iter().filter(|x| !x.is_stripped()).map(|i| from_item_id(i.item_id)).collect()
 }
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index 126c5d89ca97c..e6e5bba7f0067 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -54,7 +54,7 @@ impl<'tcx> JsonRenderer<'tcx> {
                     .map(|i| {
                         let item = &i.impl_item;
                         self.item(item.clone()).unwrap();
-                        from_item_id(item.def_id)
+                        from_item_id(item.item_id)
                     })
                     .collect()
             })
@@ -84,9 +84,9 @@ impl<'tcx> JsonRenderer<'tcx> {
                             }
                         }
 
-                        if item.def_id.is_local() || is_primitive_impl {
+                        if item.item_id.is_local() || is_primitive_impl {
                             self.item(item.clone()).unwrap();
-                            Some(from_item_id(item.def_id))
+                            Some(from_item_id(item.item_id))
                         } else {
                             None
                         }
@@ -176,18 +176,18 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
         // Flatten items that recursively store other items
         item.kind.inner_items().for_each(|i| self.item(i.clone()).unwrap());
 
-        let id = item.def_id;
+        let item_id = item.item_id;
         if let Some(mut new_item) = self.convert_item(item) {
             if let types::ItemEnum::Trait(ref mut t) = new_item.inner {
-                t.implementations = self.get_trait_implementors(id.expect_def_id())
+                t.implementations = self.get_trait_implementors(item_id.expect_def_id())
             } else if let types::ItemEnum::Struct(ref mut s) = new_item.inner {
-                s.impls = self.get_impls(id.expect_def_id())
+                s.impls = self.get_impls(item_id.expect_def_id())
             } else if let types::ItemEnum::Enum(ref mut e) = new_item.inner {
-                e.impls = self.get_impls(id.expect_def_id())
+                e.impls = self.get_impls(item_id.expect_def_id())
             } else if let types::ItemEnum::Union(ref mut u) = new_item.inner {
-                u.impls = self.get_impls(id.expect_def_id())
+                u.impls = self.get_impls(item_id.expect_def_id())
             }
-            let removed = self.index.borrow_mut().insert(from_item_id(id), new_item.clone());
+            let removed = self.index.borrow_mut().insert(from_item_id(item_id), new_item.clone());
 
             // FIXME(adotinthevoid): Currently, the index is duplicated. This is a sanity check
             // to make sure the items are unique. The main place this happens is when an item, is
diff --git a/src/librustdoc/passes/bare_urls.rs b/src/librustdoc/passes/bare_urls.rs
index 81f371840ae46..1839a35a8b14b 100644
--- a/src/librustdoc/passes/bare_urls.rs
+++ b/src/librustdoc/passes/bare_urls.rs
@@ -61,7 +61,7 @@ crate fn check_bare_urls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
 
 impl<'a, 'tcx> DocVisitor for BareUrlsLinter<'a, 'tcx> {
     fn visit_item(&mut self, item: &Item) {
-        let Some(hir_id) = DocContext::as_local_hir_id(self.cx.tcx, item.def_id)
+        let Some(hir_id) = DocContext::as_local_hir_id(self.cx.tcx, item.item_id)
         else {
             // If non-local, no need to check anything.
             return;
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index 6111c982de922..33d83aa339d95 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -185,7 +185,7 @@ impl<'a, 'b> CoverageCalculator<'a, 'b> {
 
 impl<'a, 'b> DocVisitor for CoverageCalculator<'a, 'b> {
     fn visit_item(&mut self, i: &clean::Item) {
-        if !i.def_id.is_local() {
+        if !i.item_id.is_local() {
             // non-local items are skipped because they can be out of the users control,
             // especially in the case of trait impls, which rustdoc eagerly inlines
             return;
@@ -223,7 +223,7 @@ impl<'a, 'b> DocVisitor for CoverageCalculator<'a, 'b> {
                     .ctx
                     .tcx
                     .hir()
-                    .local_def_id_to_hir_id(i.def_id.expect_def_id().expect_local());
+                    .local_def_id_to_hir_id(i.item_id.expect_def_id().expect_local());
                 let (level, source) = self.ctx.tcx.lint_level_at_node(MISSING_DOCS, hir_id);
 
                 // In case we have:
@@ -237,7 +237,7 @@ impl<'a, 'b> DocVisitor for CoverageCalculator<'a, 'b> {
                 // there is no need to require documentation on the fields of tuple variants and
                 // tuple structs.
                 let should_be_ignored = i
-                    .def_id
+                    .item_id
                     .as_def_id()
                     .and_then(|def_id| self.ctx.tcx.parent(def_id))
                     .and_then(|def_id| self.ctx.tcx.hir().get_if_local(def_id))
diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs
index d66dfca07f186..23d947c4d7227 100644
--- a/src/librustdoc/passes/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/check_code_block_syntax.rs
@@ -69,7 +69,7 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
             return;
         }
 
-        let Some(local_id) = item.def_id.as_def_id().and_then(|x| x.as_local())
+        let Some(local_id) = item.item_id.as_def_id().and_then(|x| x.as_local())
         else {
             // We don't need to check the syntax for other crates so returning
             // without doing anything should not be a problem.
@@ -153,7 +153,7 @@ impl<'a, 'tcx> DocVisitor for SyntaxChecker<'a, 'tcx> {
             let sp = item.attr_span(self.cx.tcx);
             let extra = crate::html::markdown::ExtraInfo::new_did(
                 self.cx.tcx,
-                item.def_id.expect_def_id(),
+                item.item_id.expect_def_id(),
                 sp,
             );
             for code_block in markdown::rust_code_blocks(dox, &extra) {
diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs
index b541fb63bd413..80a2683fde7f4 100644
--- a/src/librustdoc/passes/check_doc_test_visibility.rs
+++ b/src/librustdoc/passes/check_doc_test_visibility.rs
@@ -56,7 +56,7 @@ impl crate::doctest::Tester for Tests {
 }
 
 crate fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> bool {
-    if !cx.cache.access_levels.is_public(item.def_id.expect_def_id())
+    if !cx.cache.access_levels.is_public(item.item_id.expect_def_id())
         || matches!(
             *item.kind,
             clean::StructFieldItem(_)
@@ -79,7 +79,7 @@ crate fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> boo
 
     // The `expect_def_id()` should be okay because `local_def_id_to_hir_id`
     // would presumably panic if a fake `DefIndex` were passed.
-    let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.def_id.expect_def_id().expect_local());
+    let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.item_id.expect_def_id().expect_local());
 
     // check if parent is trait impl
     if let Some(parent_hir_id) = cx.tcx.hir().find_parent_node(hir_id) {
@@ -107,7 +107,7 @@ crate fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> boo
 }
 
 crate fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) {
-    let Some(hir_id) = DocContext::as_local_hir_id(cx.tcx, item.def_id)
+    let Some(hir_id) = DocContext::as_local_hir_id(cx.tcx, item.item_id)
     else {
         // If non-local, no need to check anything.
         return;
@@ -131,7 +131,7 @@ crate fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) {
             );
         }
     } else if tests.found_tests > 0
-        && !cx.cache.access_levels.is_exported(item.def_id.expect_def_id())
+        && !cx.cache.access_levels.is_exported(item.item_id.expect_def_id())
     {
         cx.tcx.struct_span_lint_hir(
             crate::lint::PRIVATE_DOC_TESTS,
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index c1b1139ad8cf9..c48f8bd0c7cc5 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -1025,15 +1025,15 @@ fn is_derive_trait_collision<T>(ns: &PerNS<Result<(Res, T), ResolutionFailure<'_
 impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> {
     fn visit_item(&mut self, item: &Item) {
         let parent_node =
-            item.def_id.as_def_id().and_then(|did| find_nearest_parent_module(self.cx.tcx, did));
+            item.item_id.as_def_id().and_then(|did| find_nearest_parent_module(self.cx.tcx, did));
         if parent_node.is_some() {
-            trace!("got parent node for {:?} {:?}, id {:?}", item.type_(), item.name, item.def_id);
+            trace!("got parent node for {:?} {:?}, id {:?}", item.type_(), item.name, item.item_id);
         }
 
         let inner_docs = item.inner_docs(self.cx.tcx);
 
         if item.is_mod() && inner_docs {
-            self.mod_ids.push(item.def_id.expect_def_id());
+            self.mod_ids.push(item.item_id.expect_def_id());
         }
 
         // We want to resolve in the lexical scope of the documentation.
@@ -1048,14 +1048,14 @@ impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> {
             for md_link in markdown_links(&doc) {
                 let link = self.resolve_link(&item, &doc, parent_node, md_link);
                 if let Some(link) = link {
-                    self.cx.cache.intra_doc_links.entry(item.def_id).or_default().push(link);
+                    self.cx.cache.intra_doc_links.entry(item.item_id).or_default().push(link);
                 }
             }
         }
 
         if item.is_mod() {
             if !inner_docs {
-                self.mod_ids.push(item.def_id.expect_def_id());
+                self.mod_ids.push(item.item_id.expect_def_id());
             }
 
             self.visit_item_recur(item);
@@ -1246,7 +1246,7 @@ impl LinkCollector<'_, '_> {
 
         let (mut res, fragment) = self.resolve_with_disambiguator_cached(
             ResolutionInfo {
-                item_id: item.def_id,
+                item_id: item.item_id,
                 module_id,
                 dis: disambiguator,
                 path_str: path_str.to_owned(),
@@ -1302,7 +1302,7 @@ impl LinkCollector<'_, '_> {
                     // FIXME: it would be nice to check that the feature gate was enabled in the original crate, not just ignore it altogether.
                     // However I'm not sure how to check that across crates.
                     if prim == PrimitiveType::RawPointer
-                        && item.def_id.is_local()
+                        && item.item_id.is_local()
                         && !self.cx.tcx.features().intra_doc_pointers
                     {
                         self.report_rawptr_assoc_feature_gate(dox, &ori_link, item);
@@ -1386,7 +1386,7 @@ impl LinkCollector<'_, '_> {
             // The `expect_def_id()` should be okay because `local_def_id_to_hir_id`
             // would presumably panic if a fake `DefIndex` were passed.
             .and_then(|dst_id| {
-                item.def_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id))
+                item.item_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id))
             })
         {
             if self.cx.tcx.privacy_access_levels(()).is_exported(src_id)
@@ -1864,7 +1864,7 @@ fn report_diagnostic(
     DiagnosticInfo { item, ori_link: _, dox, link_range }: &DiagnosticInfo<'_>,
     decorate: impl FnOnce(&mut Diagnostic, Option<rustc_span::Span>),
 ) {
-    let Some(hir_id) = DocContext::as_local_hir_id(tcx, item.def_id)
+    let Some(hir_id) = DocContext::as_local_hir_id(tcx, item.item_id)
     else {
         // If non-local, no need to check anything.
         info!("ignoring warning from parent crate: {}", msg);
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index 4ab942c8f1bdc..65459913eeaa8 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -52,7 +52,7 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
                 // FIXME(eddyb) is this `doc(hidden)` check needed?
                 if !cx.tcx.is_doc_hidden(def_id) {
                     let impls = get_auto_trait_and_blanket_impls(cx, def_id);
-                    new_items.extend(impls.filter(|i| cx.inlined.insert(i.def_id)));
+                    new_items.extend(impls.filter(|i| cx.inlined.insert(i.item_id)));
                 }
             }
         }
@@ -176,9 +176,9 @@ impl<'a, 'tcx> DocVisitor for SyntheticImplCollector<'a, 'tcx> {
     fn visit_item(&mut self, i: &Item) {
         if i.is_struct() || i.is_enum() || i.is_union() {
             // FIXME(eddyb) is this `doc(hidden)` check needed?
-            if !self.cx.tcx.is_doc_hidden(i.def_id.expect_def_id()) {
+            if !self.cx.tcx.is_doc_hidden(i.item_id.expect_def_id()) {
                 self.impls
-                    .extend(get_auto_trait_and_blanket_impls(self.cx, i.def_id.expect_def_id()));
+                    .extend(get_auto_trait_and_blanket_impls(self.cx, i.item_id.expect_def_id()));
             }
         }
 
@@ -199,7 +199,7 @@ impl ItemCollector {
 
 impl DocVisitor for ItemCollector {
     fn visit_item(&mut self, i: &Item) {
-        self.items.insert(i.def_id);
+        self.items.insert(i.item_id);
 
         self.visit_item_recur(i)
     }
@@ -225,7 +225,7 @@ impl<'a> BadImplStripper<'a> {
         }
     }
 
-    fn keep_impl_with_def_id(&self, did: ItemId) -> bool {
-        self.items.contains(&did)
+    fn keep_impl_with_def_id(&self, item_id: ItemId) -> bool {
+        self.items.contains(&item_id)
     }
 }
diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs
index a620ffa987860..044f224e7885c 100644
--- a/src/librustdoc/passes/html_tags.rs
+++ b/src/librustdoc/passes/html_tags.rs
@@ -197,7 +197,7 @@ fn extract_tags(
 impl<'a, 'tcx> DocVisitor for InvalidHtmlTagsLinter<'a, 'tcx> {
     fn visit_item(&mut self, item: &Item) {
         let tcx = self.cx.tcx;
-        let Some(hir_id) = DocContext::as_local_hir_id(tcx, item.def_id)
+        let Some(hir_id) = DocContext::as_local_hir_id(tcx, item.item_id)
         // If non-local, no need to check anything.
         else { return };
         let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs
index e7a99ee7bfd84..6b052185bbdb8 100644
--- a/src/librustdoc/passes/strip_hidden.rs
+++ b/src/librustdoc/passes/strip_hidden.rs
@@ -53,7 +53,7 @@ impl<'a> DocFolder for Stripper<'a> {
             }
         } else {
             if self.update_retained {
-                self.retained.insert(i.def_id);
+                self.retained.insert(i.item_id);
             }
         }
         Some(self.fold_item_recur(i))
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
index 82627aaf7a4cb..6a522bdacf997 100644
--- a/src/librustdoc/passes/stripper.rs
+++ b/src/librustdoc/passes/stripper.rs
@@ -45,7 +45,8 @@ impl<'a> DocFolder for Stripper<'a> {
             | clean::TraitAliasItem(..)
             | clean::MacroItem(..)
             | clean::ForeignTypeItem => {
-                if i.def_id.is_local() && !self.access_levels.is_exported(i.def_id.expect_def_id())
+                if i.item_id.is_local()
+                    && !self.access_levels.is_exported(i.item_id.expect_def_id())
                 {
                     debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name);
                     return None;
@@ -59,7 +60,7 @@ impl<'a> DocFolder for Stripper<'a> {
             }
 
             clean::ModuleItem(..) => {
-                if i.def_id.is_local() && !i.visibility.is_public() {
+                if i.item_id.is_local() && !i.visibility.is_public() {
                     debug!("Stripper: stripping module {:?}", i.name);
                     let old = mem::replace(&mut self.update_retained, false);
                     let ret = strip_item(self.fold_item_recur(i));
@@ -100,7 +101,7 @@ impl<'a> DocFolder for Stripper<'a> {
 
         let i = if fastreturn {
             if self.update_retained {
-                self.retained.insert(i.def_id);
+                self.retained.insert(i.item_id);
             }
             return Some(i);
         } else {
@@ -108,7 +109,7 @@ impl<'a> DocFolder for Stripper<'a> {
         };
 
         if self.update_retained {
-            self.retained.insert(i.def_id);
+            self.retained.insert(i.item_id);
         }
         Some(i)
     }
diff --git a/src/test/pretty/stmt_expr_attributes.rs b/src/test/pretty/stmt_expr_attributes.rs
index 7ab22f1960c2d..c01379065d1cd 100644
--- a/src/test/pretty/stmt_expr_attributes.rs
+++ b/src/test/pretty/stmt_expr_attributes.rs
@@ -1,6 +1,8 @@
 // pp-exact
 
 #![feature(box_syntax)]
+#![feature(inline_const)]
+#![feature(inline_const_pat)]
 #![feature(rustc_attrs)]
 #![feature(stmt_expr_attributes)]
 
@@ -16,6 +18,7 @@ fn _1() {
 
     #[rustc_dummy]
     unsafe {
+        #![rustc_dummy]
         // code
     }
 }
@@ -206,6 +209,12 @@ fn _11() {
             let _ = ();
             ()
         };
+    let const {
+                    #![rustc_dummy]
+                } =
+        #[rustc_dummy] const {
+                #![rustc_dummy]
+            };
     let mut x = 0;
     let _ = #[rustc_dummy] x = 15;
     let _ = #[rustc_dummy] x += 15;
diff --git a/src/test/ui/thread-local/non-static.rs b/src/test/ui/thread-local/non-static.rs
new file mode 100644
index 0000000000000..f1c4273870bff
--- /dev/null
+++ b/src/test/ui/thread-local/non-static.rs
@@ -0,0 +1,30 @@
+// Check that #[thread_local] attribute is rejected on non-static items.
+#![feature(thread_local)]
+
+#[thread_local]
+//~^ ERROR attribute should be applied to a static
+const A: u32 = 0;
+
+#[thread_local]
+//~^ ERROR attribute should be applied to a static
+fn main() {
+    #[thread_local] || {};
+    //~^ ERROR attribute should be applied to a static
+}
+
+struct S {
+    #[thread_local]
+    //~^ ERROR attribute should be applied to a static
+    a: String,
+    b: String,
+}
+
+#[thread_local]
+// Static. OK.
+static B: u32 = 0;
+
+extern "C" {
+    #[thread_local]
+    // Foreign static. OK.
+    static C: u32;
+}
diff --git a/src/test/ui/thread-local/non-static.stderr b/src/test/ui/thread-local/non-static.stderr
new file mode 100644
index 0000000000000..09a1618d6e710
--- /dev/null
+++ b/src/test/ui/thread-local/non-static.stderr
@@ -0,0 +1,38 @@
+error: attribute should be applied to a static
+  --> $DIR/non-static.rs:4:1
+   |
+LL | #[thread_local]
+   | ^^^^^^^^^^^^^^^
+LL |
+LL | const A: u32 = 0;
+   | ----------------- not a static
+
+error: attribute should be applied to a static
+  --> $DIR/non-static.rs:8:1
+   |
+LL |   #[thread_local]
+   |   ^^^^^^^^^^^^^^^
+LL |
+LL | / fn main() {
+LL | |     #[thread_local] || {};
+LL | |
+LL | | }
+   | |_- not a static
+
+error: attribute should be applied to a static
+  --> $DIR/non-static.rs:11:5
+   |
+LL |     #[thread_local] || {};
+   |     ^^^^^^^^^^^^^^^ ----- not a static
+
+error: attribute should be applied to a static
+  --> $DIR/non-static.rs:16:5
+   |
+LL |     #[thread_local]
+   |     ^^^^^^^^^^^^^^^
+LL |
+LL |     a: String,
+   |     --------- not a static
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml
index b8c67de26230b..f074eb941dca2 100644
--- a/src/tools/rustbook/Cargo.toml
+++ b/src/tools/rustbook/Cargo.toml
@@ -9,6 +9,6 @@ clap = "2.25.0"
 env_logger = "0.7.1"
 
 [dependencies.mdbook]
-version = "0.4.14"
+version = "0.4.18"
 default-features = false
 features = ["search"]