about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-11-21 20:18:11 +0000
committerbors <bors@rust-lang.org>2020-11-21 20:18:11 +0000
commitda384694807172f0ca40eca2e49a11688aba6e93 (patch)
treeb1b379214fe7fc680444775c1514583c70d71bea
parent3adedb8f4c5bb71e9e8a21a047cf8ed121ce0e75 (diff)
parent68c9caa6f69d015f39a25e5acbcf90f9a72c7287 (diff)
downloadrust-da384694807172f0ca40eca2e49a11688aba6e93.tar.gz
rust-da384694807172f0ca40eca2e49a11688aba6e93.zip
Auto merge of #79273 - Dylan-DPC:rollup-zd10xlt, r=Dylan-DPC
Rollup of 8 pull requests

Successful merges:

 - #77844 (clarify rules for ZST Boxes)
 - #79067 (Refactor the abi handling code a bit)
 - #79182 (Fix links to extern types in rustdoc (fixes #78777))
 - #79231 (Exhaustively match in variant count instrinsic)
 - #79238 (Direct RUSTC_LOG (tracing/log) output to stderr instead of stdout.)
 - #79256 (Fix typos)
 - #79264 (Get rid of some doctree items)
 - #79272 (Support building clone shims for arrays with generic size)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs146
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs4
-rw-r--r--compiler/rustc_driver/src/lib.rs1
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs7
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs7
-rw-r--r--compiler/rustc_mir/src/interpret/intrinsics.rs36
-rw-r--r--compiler/rustc_mir/src/shim.rs19
-rw-r--r--compiler/rustc_query_system/src/query/job.rs6
-rw-r--r--compiler/rustc_target/src/abi/call/mips64.rs6
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs61
-rw-r--r--compiler/rustc_target/src/abi/call/riscv.rs4
-rw-r--r--compiler/rustc_target/src/abi/call/x86.rs9
-rw-r--r--library/alloc/src/boxed.rs11
-rw-r--r--library/core/src/ptr/mod.rs8
-rw-r--r--src/librustdoc/clean/mod.rs185
-rw-r--r--src/librustdoc/doctree.rs83
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs9
-rw-r--r--src/librustdoc/visit_ast.rs91
-rw-r--r--src/test/rustdoc-ui/doc-without-codeblock.stderr12
-rw-r--r--src/test/rustdoc-ui/intra-links-ambiguity.stderr38
-rw-r--r--src/test/rustdoc-ui/intra-links-warning.stderr108
-rw-r--r--src/test/rustdoc-ui/lint-missing-doc-code-example.stderr28
-rw-r--r--src/test/rustdoc/intra-link-extern-type.rs18
-rw-r--r--src/test/rustdoc/redirect-rename.rs12
-rw-r--r--src/test/ui/consts/issue-79137-monomorphic.rs19
-rw-r--r--src/test/ui/consts/issue-79137-toogeneric.rs19
-rw-r--r--src/test/ui/consts/issue-79137-toogeneric.stderr14
-rw-r--r--src/test/ui/mir/mir-inlining/array-clone-with-generic-size.rs13
28 files changed, 499 insertions, 475 deletions
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 7857ccb613b..915dd3d9eda 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -36,17 +36,17 @@ impl ArgAttributeExt for ArgAttribute {
     where
         F: FnMut(llvm::Attribute),
     {
-        for_each_kind!(self, f, NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt, InReg)
+        for_each_kind!(self, f, NoAlias, NoCapture, NonNull, ReadOnly, InReg)
     }
 }
 
 pub trait ArgAttributesExt {
-    fn apply_llfn(&self, idx: AttributePlace, llfn: &Value, ty: Option<&Type>);
-    fn apply_callsite(&self, idx: AttributePlace, callsite: &Value, ty: Option<&Type>);
+    fn apply_attrs_to_llfn(&self, idx: AttributePlace, llfn: &Value);
+    fn apply_attrs_to_callsite(&self, idx: AttributePlace, callsite: &Value);
 }
 
 impl ArgAttributesExt for ArgAttributes {
-    fn apply_llfn(&self, idx: AttributePlace, llfn: &Value, ty: Option<&Type>) {
+    fn apply_attrs_to_llfn(&self, idx: AttributePlace, llfn: &Value) {
         let mut regular = self.regular;
         unsafe {
             let deref = self.pointee_size.bytes();
@@ -61,14 +61,20 @@ impl ArgAttributesExt for ArgAttributes {
             if let Some(align) = self.pointee_align {
                 llvm::LLVMRustAddAlignmentAttr(llfn, idx.as_uint(), align.bytes() as u32);
             }
-            if regular.contains(ArgAttribute::ByVal) {
-                llvm::LLVMRustAddByValAttr(llfn, idx.as_uint(), ty.unwrap());
-            }
             regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn));
+            match self.arg_ext {
+                ArgExtension::None => {}
+                ArgExtension::Zext => {
+                    llvm::Attribute::ZExt.apply_llfn(idx, llfn);
+                }
+                ArgExtension::Sext => {
+                    llvm::Attribute::SExt.apply_llfn(idx, llfn);
+                }
+            }
         }
     }
 
-    fn apply_callsite(&self, idx: AttributePlace, callsite: &Value, ty: Option<&Type>) {
+    fn apply_attrs_to_callsite(&self, idx: AttributePlace, callsite: &Value) {
         let mut regular = self.regular;
         unsafe {
             let deref = self.pointee_size.bytes();
@@ -91,10 +97,16 @@ impl ArgAttributesExt for ArgAttributes {
                     align.bytes() as u32,
                 );
             }
-            if regular.contains(ArgAttribute::ByVal) {
-                llvm::LLVMRustAddByValCallSiteAttr(callsite, idx.as_uint(), ty.unwrap());
-            }
             regular.for_each_kind(|attr| attr.apply_callsite(idx, callsite));
+            match self.arg_ext {
+                ArgExtension::None => {}
+                ArgExtension::Zext => {
+                    llvm::Attribute::ZExt.apply_callsite(idx, callsite);
+                }
+                ArgExtension::Sext => {
+                    llvm::Attribute::SExt.apply_callsite(idx, callsite);
+                }
+            }
         }
     }
 }
@@ -146,7 +158,7 @@ impl LlvmType for CastTarget {
             .prefix
             .iter()
             .flat_map(|option_kind| {
-                option_kind.map(|kind| Reg { kind, size: self.prefix_chunk }.llvm_type(cx))
+                option_kind.map(|kind| Reg { kind, size: self.prefix_chunk_size }.llvm_type(cx))
             })
             .chain((0..rest_count).map(|_| rest_ll_unit))
             .collect();
@@ -267,10 +279,12 @@ impl ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
             PassMode::Pair(..) => {
                 OperandValue::Pair(next(), next()).store(bx, dst);
             }
-            PassMode::Indirect(_, Some(_)) => {
+            PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
                 OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst);
             }
-            PassMode::Direct(_) | PassMode::Indirect(_, None) | PassMode::Cast(_) => {
+            PassMode::Direct(_)
+            | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ }
+            | PassMode::Cast(_) => {
                 let next_arg = next();
                 self.store(bx, next_arg, dst);
             }
@@ -315,14 +329,14 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
             if let PassMode::Pair(_, _) = arg.mode { 2 } else { 1 }
         ).sum();
         let mut llargument_tys = Vec::with_capacity(
-            if let PassMode::Indirect(..) = self.ret.mode { 1 } else { 0 } + args_capacity,
+            if let PassMode::Indirect { .. } = self.ret.mode { 1 } else { 0 } + args_capacity,
         );
 
         let llreturn_ty = match self.ret.mode {
             PassMode::Ignore => cx.type_void(),
             PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_llvm_type(cx),
             PassMode::Cast(cast) => cast.llvm_type(cx),
-            PassMode::Indirect(..) => {
+            PassMode::Indirect { .. } => {
                 llargument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx)));
                 cx.type_void()
             }
@@ -342,7 +356,7 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
                     llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true));
                     continue;
                 }
-                PassMode::Indirect(_, Some(_)) => {
+                PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
                     let ptr_ty = cx.tcx.mk_mut_ptr(arg.layout.ty);
                     let ptr_layout = cx.layout_of(ptr_ty);
                     llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 0, true));
@@ -350,7 +364,9 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
                     continue;
                 }
                 PassMode::Cast(cast) => cast.llvm_type(cx),
-                PassMode::Indirect(_, None) => cx.type_ptr_to(arg.memory_ty(cx)),
+                PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
+                    cx.type_ptr_to(arg.memory_ty(cx))
+                }
             };
             llargument_tys.push(llarg_ty);
         }
@@ -402,35 +418,54 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
         }
 
         let mut i = 0;
-        let mut apply = |attrs: &ArgAttributes, ty: Option<&Type>| {
-            attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn, ty);
+        let mut apply = |attrs: &ArgAttributes| {
+            attrs.apply_attrs_to_llfn(llvm::AttributePlace::Argument(i), llfn);
             i += 1;
+            i - 1
         };
         match self.ret.mode {
             PassMode::Direct(ref attrs) => {
-                attrs.apply_llfn(llvm::AttributePlace::ReturnValue, llfn, None);
+                attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, llfn);
+            }
+            PassMode::Indirect { ref attrs, extra_attrs: _, on_stack } => {
+                assert!(!on_stack);
+                let i = apply(attrs);
+                llvm::Attribute::StructRet.apply_llfn(llvm::AttributePlace::Argument(i), llfn);
             }
-            PassMode::Indirect(ref attrs, _) => apply(attrs, Some(self.ret.layout.llvm_type(cx))),
             _ => {}
         }
         for arg in &self.args {
             if arg.pad.is_some() {
-                apply(&ArgAttributes::new(), None);
+                apply(&ArgAttributes::new());
             }
             match arg.mode {
                 PassMode::Ignore => {}
-                PassMode::Direct(ref attrs) | PassMode::Indirect(ref attrs, None) => {
-                    apply(attrs, Some(arg.layout.llvm_type(cx)))
+                PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: true } => {
+                    let i = apply(attrs);
+                    unsafe {
+                        llvm::LLVMRustAddByValAttr(
+                            llfn,
+                            llvm::AttributePlace::Argument(i).as_uint(),
+                            arg.layout.llvm_type(cx),
+                        );
+                    }
                 }
-                PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => {
-                    apply(attrs, None);
-                    apply(extra_attrs, None);
+                PassMode::Direct(ref attrs)
+                | PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: false } => {
+                    apply(attrs);
+                }
+                PassMode::Indirect { ref attrs, extra_attrs: Some(ref extra_attrs), on_stack } => {
+                    assert!(!on_stack);
+                    apply(attrs);
+                    apply(extra_attrs);
                 }
                 PassMode::Pair(ref a, ref b) => {
-                    apply(a, None);
-                    apply(b, None);
+                    apply(a);
+                    apply(b);
+                }
+                PassMode::Cast(_) => {
+                    apply(&ArgAttributes::new());
                 }
-                PassMode::Cast(_) => apply(&ArgAttributes::new(), None),
             }
         }
     }
@@ -439,15 +474,21 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
         // FIXME(wesleywiser, eddyb): We should apply `nounwind` and `noreturn` as appropriate to this callsite.
 
         let mut i = 0;
-        let mut apply = |attrs: &ArgAttributes, ty: Option<&Type>| {
-            attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite, ty);
+        let mut apply = |attrs: &ArgAttributes| {
+            attrs.apply_attrs_to_callsite(llvm::AttributePlace::Argument(i), callsite);
             i += 1;
+            i - 1
         };
         match self.ret.mode {
             PassMode::Direct(ref attrs) => {
-                attrs.apply_callsite(llvm::AttributePlace::ReturnValue, callsite, None);
+                attrs.apply_attrs_to_callsite(llvm::AttributePlace::ReturnValue, callsite);
+            }
+            PassMode::Indirect { ref attrs, extra_attrs: _, on_stack } => {
+                assert!(!on_stack);
+                let i = apply(attrs);
+                llvm::Attribute::StructRet
+                    .apply_callsite(llvm::AttributePlace::Argument(i), callsite);
             }
-            PassMode::Indirect(ref attrs, _) => apply(attrs, Some(self.ret.layout.llvm_type(bx))),
             _ => {}
         }
         if let abi::Abi::Scalar(ref scalar) = self.ret.layout.abi {
@@ -465,22 +506,39 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
         }
         for arg in &self.args {
             if arg.pad.is_some() {
-                apply(&ArgAttributes::new(), None);
+                apply(&ArgAttributes::new());
             }
             match arg.mode {
                 PassMode::Ignore => {}
-                PassMode::Direct(ref attrs) | PassMode::Indirect(ref attrs, None) => {
-                    apply(attrs, Some(arg.layout.llvm_type(bx)))
+                PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: true } => {
+                    let i = apply(attrs);
+                    unsafe {
+                        llvm::LLVMRustAddByValCallSiteAttr(
+                            callsite,
+                            llvm::AttributePlace::Argument(i).as_uint(),
+                            arg.layout.llvm_type(bx),
+                        );
+                    }
                 }
-                PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => {
-                    apply(attrs, None);
-                    apply(extra_attrs, None);
+                PassMode::Direct(ref attrs)
+                | PassMode::Indirect { ref attrs, extra_attrs: None, on_stack: false } => {
+                    apply(attrs);
+                }
+                PassMode::Indirect {
+                    ref attrs,
+                    extra_attrs: Some(ref extra_attrs),
+                    on_stack: _,
+                } => {
+                    apply(attrs);
+                    apply(extra_attrs);
                 }
                 PassMode::Pair(ref a, ref b) => {
-                    apply(a, None);
-                    apply(b, None);
+                    apply(a);
+                    apply(b);
+                }
+                PassMode::Cast(_) => {
+                    apply(&ArgAttributes::new());
                 }
-                PassMode::Cast(_) => apply(&ArgAttributes::new(), None),
             }
         }
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index ee40095883d..fd20709f5d8 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -255,7 +255,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             return;
         }
         let llval = match self.fn_abi.ret.mode {
-            PassMode::Ignore | PassMode::Indirect(..) => {
+            PassMode::Ignore | PassMode::Indirect { .. } => {
                 bx.ret_void();
                 return;
             }
@@ -1101,7 +1101,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         // Force by-ref if we have to load through a cast pointer.
         let (mut llval, align, by_ref) = match op.val {
             Immediate(_) | Pair(..) => match arg.mode {
-                PassMode::Indirect(..) | PassMode::Cast(_) => {
+                PassMode::Indirect { .. } | PassMode::Cast(_) => {
                     let scratch = PlaceRef::alloca(bx, arg.layout);
                     op.val.store(bx, scratch);
                     (scratch.llval, scratch.align, true)
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index c5447612555..e49e456792b 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -1286,6 +1286,7 @@ pub fn init_env_logger(env: &str) {
     }
     let filter = tracing_subscriber::EnvFilter::from_env(env);
     let layer = tracing_tree::HierarchicalLayer::default()
+        .with_writer(io::stderr)
         .with_indent_lines(true)
         .with_ansi(true)
         .with_targets(true)
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index a1df1a63fc5..19340dd51de 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -947,7 +947,12 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
     }
 
     fn get_type(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
-        self.root.tables.ty.get(self, id).unwrap().decode((self, tcx))
+        self.root
+            .tables
+            .ty
+            .get(self, id)
+            .unwrap_or_else(|| panic!("Not a type: {:?}", id))
+            .decode((self, tcx))
     }
 
     fn get_stability(&self, id: DefIndex) -> Option<attr::Stability> {
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 5626c864fe1..fa0711193df 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -15,7 +15,7 @@ use rustc_session::{DataTypeKind, FieldInfo, SizeKind, VariantInfo};
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::DUMMY_SP;
 use rustc_target::abi::call::{
-    ArgAbi, ArgAttribute, ArgAttributes, Conv, FnAbi, PassMode, Reg, RegKind,
+    ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind,
 };
 use rustc_target::abi::*;
 use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy};
@@ -2619,7 +2619,7 @@ where
                                       is_return: bool| {
             // Booleans are always an i1 that needs to be zero-extended.
             if scalar.is_bool() {
-                attrs.set(ArgAttribute::ZExt);
+                attrs.ext(ArgExtension::Zext);
                 return;
             }
 
@@ -2801,9 +2801,6 @@ where
             for arg in &mut self.args {
                 fixup(arg, false);
             }
-            if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode {
-                attrs.set(ArgAttribute::StructRet);
-            }
             return;
         }
 
diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs
index d3b6d706337..f666a89ca56 100644
--- a/compiler/rustc_mir/src/interpret/intrinsics.rs
+++ b/compiler/rustc_mir/src/interpret/intrinsics.rs
@@ -75,13 +75,35 @@ crate fn eval_nullary_intrinsic<'tcx>(
             ensure_monomorphic_enough(tcx, tp_ty)?;
             ConstValue::from_u64(tcx.type_id_hash(tp_ty))
         }
-        sym::variant_count => {
-            if let ty::Adt(ref adt, _) = tp_ty.kind() {
-                ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx)
-            } else {
-                ConstValue::from_machine_usize(0u64, &tcx)
-            }
-        }
+        sym::variant_count => match tp_ty.kind() {
+            ty::Adt(ref adt, _) => ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx),
+            ty::Projection(_)
+            | ty::Opaque(_, _)
+            | ty::Param(_)
+            | ty::Bound(_, _)
+            | ty::Placeholder(_)
+            | ty::Infer(_) => throw_inval!(TooGeneric),
+            ty::Bool
+            | ty::Char
+            | ty::Int(_)
+            | ty::Uint(_)
+            | ty::Float(_)
+            | ty::Foreign(_)
+            | ty::Str
+            | ty::Array(_, _)
+            | ty::Slice(_)
+            | ty::RawPtr(_)
+            | ty::Ref(_, _, _)
+            | ty::FnDef(_, _)
+            | ty::FnPtr(_)
+            | ty::Dynamic(_, _)
+            | ty::Closure(_, _)
+            | ty::Generator(_, _, _)
+            | ty::GeneratorWitness(_)
+            | ty::Never
+            | ty::Tuple(_)
+            | ty::Error(_) => ConstValue::from_machine_usize(0u64, &tcx),
+        },
         other => bug!("`{}` is not a zero arg intrinsic", other),
     })
 }
diff --git a/compiler/rustc_mir/src/shim.rs b/compiler/rustc_mir/src/shim.rs
index 3a1fa0018c1..aa5835686a2 100644
--- a/compiler/rustc_mir/src/shim.rs
+++ b/compiler/rustc_mir/src/shim.rs
@@ -308,10 +308,7 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -
 
     match self_ty.kind() {
         _ if is_copy => builder.copy_shim(),
-        ty::Array(ty, len) => {
-            let len = len.eval_usize(tcx, param_env);
-            builder.array_shim(dest, src, ty, len)
-        }
+        ty::Array(ty, len) => builder.array_shim(dest, src, ty, len),
         ty::Closure(_, substs) => {
             builder.tuple_like_shim(dest, src, substs.as_closure().upvar_tys())
         }
@@ -485,7 +482,13 @@ impl CloneShimBuilder<'tcx> {
         }
     }
 
-    fn array_shim(&mut self, dest: Place<'tcx>, src: Place<'tcx>, ty: Ty<'tcx>, len: u64) {
+    fn array_shim(
+        &mut self,
+        dest: Place<'tcx>,
+        src: Place<'tcx>,
+        ty: Ty<'tcx>,
+        len: &'tcx ty::Const<'tcx>,
+    ) {
         let tcx = self.tcx;
         let span = self.span;
 
@@ -503,7 +506,11 @@ impl CloneShimBuilder<'tcx> {
             ))),
             self.make_statement(StatementKind::Assign(box (
                 end,
-                Rvalue::Use(Operand::Constant(self.make_usize(len))),
+                Rvalue::Use(Operand::Constant(box Constant {
+                    span: self.span,
+                    user_ty: None,
+                    literal: len,
+                })),
             ))),
         ];
         self.block(inits, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index c1d3210b617..5fed500390b 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -33,11 +33,11 @@ pub struct QueryInfo<Q> {
 
 pub(crate) type QueryMap<D, Q> = FxHashMap<QueryJobId<D>, QueryJobInfo<D, Q>>;
 
-/// A value uniquely identifiying an active query job within a shard in the query cache.
+/// A value uniquely identifying an active query job within a shard in the query cache.
 #[derive(Copy, Clone, Eq, PartialEq, Hash)]
 pub struct QueryShardJobId(pub NonZeroU32);
 
-/// A value uniquely identifiying an active query job.
+/// A value uniquely identifying an active query job.
 #[derive(Copy, Clone, Eq, PartialEq, Hash)]
 pub struct QueryJobId<D> {
     /// Which job within a shard is this
@@ -536,7 +536,7 @@ fn remove_cycle<CTX: QueryContext>(
         };
 
         // We unwrap `waiter` here since there must always be one
-        // edge which is resumeable / waited using a query latch
+        // edge which is resumable / waited using a query latch
         let (waitee_query, waiter_idx) = waiter.unwrap();
 
         // Extract the waiter we want to resume
diff --git a/compiler/rustc_target/src/abi/call/mips64.rs b/compiler/rustc_target/src/abi/call/mips64.rs
index 917dd104d14..a630c84142b 100644
--- a/compiler/rustc_target/src/abi/call/mips64.rs
+++ b/compiler/rustc_target/src/abi/call/mips64.rs
@@ -1,4 +1,4 @@
-use crate::abi::call::{ArgAbi, ArgAttribute, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
+use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
 use crate::abi::{self, HasDataLayout, LayoutOf, Size, TyAndLayout, TyAndLayoutMethods};
 
 fn extend_integer_width_mips<Ty>(arg: &mut ArgAbi<'_, Ty>, bits: u64) {
@@ -7,7 +7,7 @@ fn extend_integer_width_mips<Ty>(arg: &mut ArgAbi<'_, Ty>, bits: u64) {
         if let abi::Int(i, signed) = scalar.value {
             if !signed && i.size().bits() == 32 {
                 if let PassMode::Direct(ref mut attrs) = arg.mode {
-                    attrs.set(ArgAttribute::SExt);
+                    attrs.ext(ArgExtension::Sext);
                     return;
                 }
             }
@@ -137,7 +137,7 @@ where
     let rest_size = size - Size::from_bytes(8) * prefix_index as u64;
     arg.cast_to(CastTarget {
         prefix,
-        prefix_chunk: Size::from_bytes(8),
+        prefix_chunk_size: Size::from_bytes(8),
         rest: Uniform { unit: Reg::i64(), total: rest_size },
     });
 }
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 429a3375cd8..5de9a8dfa7a 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -36,9 +36,12 @@ pub enum PassMode {
     /// a single uniform or a pair of registers.
     Cast(CastTarget),
     /// Pass the argument indirectly via a hidden pointer.
-    /// The second value, if any, is for the extra data (vtable or length)
+    /// The `extra_attrs` value, if any, is for the extra data (vtable or length)
     /// which indicates that it refers to an unsized rvalue.
-    Indirect(ArgAttributes, Option<ArgAttributes>),
+    /// `on_stack` defines that the the value should be passed at a fixed
+    /// stack offset in accordance to the ABI rather than passed using a
+    /// pointer. This corresponds to the `byval` LLVM argument attribute.
+    Indirect { attrs: ArgAttributes, extra_attrs: Option<ArgAttributes>, on_stack: bool },
 }
 
 // Hack to disable non_upper_case_globals only for the bitflags! and not for the rest
@@ -52,24 +55,31 @@ mod attr_impl {
     bitflags::bitflags! {
         #[derive(Default)]
         pub struct ArgAttribute: u16 {
-            const ByVal     = 1 << 0;
             const NoAlias   = 1 << 1;
             const NoCapture = 1 << 2;
             const NonNull   = 1 << 3;
             const ReadOnly  = 1 << 4;
-            const SExt      = 1 << 5;
-            const StructRet = 1 << 6;
-            const ZExt      = 1 << 7;
             const InReg     = 1 << 8;
         }
     }
 }
 
+/// Sometimes an ABI requires small integers to be extended to a full or partial register. This enum
+/// defines if this extension should be zero-extension or sign-extension when necssary. When it is
+/// not necesary to extend the argument, this enum is ignored.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum ArgExtension {
+    None,
+    Zext,
+    Sext,
+}
+
 /// A compact representation of LLVM attributes (at least those relevant for this module)
 /// that can be manipulated without interacting with LLVM's Attribute machinery.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub struct ArgAttributes {
     pub regular: ArgAttribute,
+    pub arg_ext: ArgExtension,
     /// The minimum size of the pointee, guaranteed to be valid for the duration of the whole call
     /// (corresponding to LLVM's dereferenceable and dereferenceable_or_null attributes).
     pub pointee_size: Size,
@@ -80,11 +90,18 @@ impl ArgAttributes {
     pub fn new() -> Self {
         ArgAttributes {
             regular: ArgAttribute::default(),
+            arg_ext: ArgExtension::None,
             pointee_size: Size::ZERO,
             pointee_align: None,
         }
     }
 
+    pub fn ext(&mut self, ext: ArgExtension) -> &mut Self {
+        assert!(self.arg_ext == ArgExtension::None || self.arg_ext == ext);
+        self.arg_ext = ext;
+        self
+    }
+
     pub fn set(&mut self, attr: ArgAttribute) -> &mut Self {
         self.regular |= attr;
         self
@@ -180,7 +197,7 @@ impl Uniform {
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub struct CastTarget {
     pub prefix: [Option<RegKind>; 8],
-    pub prefix_chunk: Size,
+    pub prefix_chunk_size: Size,
     pub rest: Uniform,
 }
 
@@ -192,7 +209,7 @@ impl From<Reg> for CastTarget {
 
 impl From<Uniform> for CastTarget {
     fn from(uniform: Uniform) -> CastTarget {
-        CastTarget { prefix: [None; 8], prefix_chunk: Size::ZERO, rest: uniform }
+        CastTarget { prefix: [None; 8], prefix_chunk_size: Size::ZERO, rest: uniform }
     }
 }
 
@@ -200,13 +217,13 @@ impl CastTarget {
     pub fn pair(a: Reg, b: Reg) -> CastTarget {
         CastTarget {
             prefix: [Some(a.kind), None, None, None, None, None, None, None],
-            prefix_chunk: a.size,
+            prefix_chunk_size: a.size,
             rest: Uniform::from(b),
         }
     }
 
     pub fn size<C: HasDataLayout>(&self, cx: &C) -> Size {
-        (self.prefix_chunk * self.prefix.iter().filter(|x| x.is_some()).count() as u64)
+        (self.prefix_chunk_size * self.prefix.iter().filter(|x| x.is_some()).count() as u64)
             .align_to(self.rest.align(cx))
             + self.rest.total
     }
@@ -214,7 +231,7 @@ impl CastTarget {
     pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
         self.prefix
             .iter()
-            .filter_map(|x| x.map(|kind| Reg { kind, size: self.prefix_chunk }.align(cx)))
+            .filter_map(|x| x.map(|kind| Reg { kind, size: self.prefix_chunk_size }.align(cx)))
             .fold(cx.data_layout().aggregate_align.abi.max(self.rest.align(cx)), |acc, align| {
                 acc.max(align)
             })
@@ -438,14 +455,14 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
 
         let extra_attrs = self.layout.is_unsized().then_some(ArgAttributes::new());
 
-        self.mode = PassMode::Indirect(attrs, extra_attrs);
+        self.mode = PassMode::Indirect { attrs, extra_attrs, on_stack: false };
     }
 
     pub fn make_indirect_byval(&mut self) {
         self.make_indirect();
         match self.mode {
-            PassMode::Indirect(ref mut attrs, _) => {
-                attrs.set(ArgAttribute::ByVal);
+            PassMode::Indirect { attrs: _, extra_attrs: _, ref mut on_stack } => {
+                *on_stack = true;
             }
             _ => unreachable!(),
         }
@@ -457,7 +474,11 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
             if let abi::Int(i, signed) = scalar.value {
                 if i.size().bits() < bits {
                     if let PassMode::Direct(ref mut attrs) = self.mode {
-                        attrs.set(if signed { ArgAttribute::SExt } else { ArgAttribute::ZExt });
+                        if signed {
+                            attrs.ext(ArgExtension::Sext)
+                        } else {
+                            attrs.ext(ArgExtension::Zext)
+                        };
                     }
                 }
             }
@@ -474,15 +495,15 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
     }
 
     pub fn is_indirect(&self) -> bool {
-        matches!(self.mode, PassMode::Indirect(..))
+        matches!(self.mode, PassMode::Indirect {..})
     }
 
     pub fn is_sized_indirect(&self) -> bool {
-        matches!(self.mode, PassMode::Indirect(_, None))
+        matches!(self.mode, PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ })
     }
 
     pub fn is_unsized_indirect(&self) -> bool {
-        matches!(self.mode, PassMode::Indirect(_, Some(_)))
+        matches!(self.mode, PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ })
     }
 
     pub fn is_ignore(&self) -> bool {
@@ -591,10 +612,6 @@ impl<'a, Ty> FnAbi<'a, Ty> {
             a => return Err(format!("unrecognized arch \"{}\" in target specification", a)),
         }
 
-        if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode {
-            attrs.set(ArgAttribute::StructRet);
-        }
-
         Ok(())
     }
 }
diff --git a/compiler/rustc_target/src/abi/call/riscv.rs b/compiler/rustc_target/src/abi/call/riscv.rs
index 782c661c31f..1ab881dd13d 100644
--- a/compiler/rustc_target/src/abi/call/riscv.rs
+++ b/compiler/rustc_target/src/abi/call/riscv.rs
@@ -4,7 +4,7 @@
 // Reference: Clang RISC-V ELF psABI lowering code
 // https://github.com/llvm/llvm-project/blob/8e780252a7284be45cf1ba224cabd884847e8e92/clang/lib/CodeGen/TargetInfo.cpp#L9311-L9773
 
-use crate::abi::call::{ArgAbi, ArgAttribute, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
+use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
 use crate::abi::{
     self, Abi, FieldsShape, HasDataLayout, LayoutOf, Size, TyAndLayout, TyAndLayoutMethods,
 };
@@ -308,7 +308,7 @@ fn extend_integer_width<'a, Ty>(arg: &mut ArgAbi<'a, Ty>, xlen: u64) {
             // 32-bit integers are always sign-extended
             if i.size().bits() == 32 && xlen > 32 {
                 if let PassMode::Direct(ref mut attrs) = arg.mode {
-                    attrs.set(ArgAttribute::SExt);
+                    attrs.ext(ArgExtension::Sext);
                     return;
                 }
             }
diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs
index 07bf1e94c61..713b4100a33 100644
--- a/compiler/rustc_target/src/abi/call/x86.rs
+++ b/compiler/rustc_target/src/abi/call/x86.rs
@@ -92,9 +92,14 @@ where
 
         for arg in &mut fn_abi.args {
             let attrs = match arg.mode {
-                PassMode::Ignore | PassMode::Indirect(_, None) => continue,
+                PassMode::Ignore
+                | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
+                    continue;
+                }
                 PassMode::Direct(ref mut attrs) => attrs,
-                PassMode::Pair(..) | PassMode::Indirect(_, Some(_)) | PassMode::Cast(_) => {
+                PassMode::Pair(..)
+                | PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ }
+                | PassMode::Cast(_) => {
                     unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode)
                 }
             };
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 1512235da6a..b9490c44f4b 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -62,6 +62,13 @@
 //! T` obtained from [`Box::<T>::into_raw`] may be deallocated using the
 //! [`Global`] allocator with [`Layout::for_value(&*value)`].
 //!
+//! For zero-sized values, the `Box` pointer still has to be [valid] for reads
+//! and writes and sufficiently aligned. In particular, casting any aligned
+//! non-zero integer literal to a raw pointer produces a valid pointer, but a
+//! pointer pointing into previously allocated memory that since got freed is
+//! not valid. The recommended way to build a Box to a ZST if `Box::new` cannot
+//! be used is to use [`ptr::NonNull::dangling`].
+//!
 //! So long as `T: Sized`, a `Box<T>` is guaranteed to be represented
 //! as a single pointer and is also ABI-compatible with C pointers
 //! (i.e. the C type `T*`). This means that if you have extern "C"
@@ -125,6 +132,7 @@
 //! [`Global`]: crate::alloc::Global
 //! [`Layout`]: crate::alloc::Layout
 //! [`Layout::for_value(&*value)`]: crate::alloc::Layout::for_value
+//! [valid]: ptr#safety
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -530,7 +538,10 @@ impl<T: ?Sized> Box<T> {
     /// memory problems. For example, a double-free may occur if the
     /// function is called twice on the same raw pointer.
     ///
+    /// The safety conditions are described in the [memory layout] section.
+    ///
     /// # Examples
+    ///
     /// Recreate a `Box` which was previously converted to a raw pointer
     /// using [`Box::into_raw`]:
     /// ```
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 9de2758767e..27d49529a5e 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -16,12 +16,16 @@
 //! provided at this point are very minimal:
 //!
 //! * A [null] pointer is *never* valid, not even for accesses of [size zero][zst].
-//! * All pointers (except for the null pointer) are valid for all operations of
-//!   [size zero][zst].
 //! * For a pointer to be valid, it is necessary, but not always sufficient, that the pointer
 //!   be *dereferenceable*: the memory range of the given size starting at the pointer must all be
 //!   within the bounds of a single allocated object. Note that in Rust,
 //!   every (stack-allocated) variable is considered a separate allocated object.
+//! * Even for operations of [size zero][zst], the pointer must not be pointing to deallocated
+//!   memory, i.e., deallocation makes pointers invalid even for zero-sized operations. However,
+//!   casting any non-zero integer *literal* to a pointer is valid for zero-sized accesses, even if
+//!   some memory happens to exist at that address and gets deallocated. This corresponds to writing
+//!   your own allocator: allocating zero-sized objects is not very hard. The canonical way to
+//!   obtain a pointer that is valid for zero-sized accesses is [`NonNull::dangling`].
 //! * All accesses performed by functions in this module are *non-atomic* in the sense
 //!   of [atomic operations] used to synchronize between threads. This means it is
 //!   undefined behavior to perform two concurrent accesses to the same location from different
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 9d84089eb40..d58a88957df 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -231,21 +231,14 @@ impl Clean<Item> for doctree::Module<'_> {
         let mut items: Vec<Item> = vec![];
         items.extend(self.extern_crates.iter().flat_map(|x| x.clean(cx)));
         items.extend(self.imports.iter().flat_map(|x| x.clean(cx)));
-        items.extend(self.structs.iter().map(|x| x.clean(cx)));
-        items.extend(self.unions.iter().map(|x| x.clean(cx)));
-        items.extend(self.enums.iter().map(|x| x.clean(cx)));
         items.extend(self.fns.iter().map(|x| x.clean(cx)));
         items.extend(self.foreigns.iter().map(|x| x.clean(cx)));
         items.extend(self.mods.iter().map(|x| x.clean(cx)));
-        items.extend(self.typedefs.iter().map(|x| x.clean(cx)));
-        items.extend(self.opaque_tys.iter().map(|x| x.clean(cx)));
-        items.extend(self.statics.iter().map(|x| x.clean(cx)));
-        items.extend(self.constants.iter().map(|x| x.clean(cx)));
+        items.extend(self.items.iter().map(|x| x.clean(cx)));
         items.extend(self.traits.iter().map(|x| x.clean(cx)));
         items.extend(self.impls.iter().flat_map(|x| x.clean(cx)));
         items.extend(self.macros.iter().map(|x| x.clean(cx)));
         items.extend(self.proc_macros.iter().map(|x| x.clean(cx)));
-        items.extend(self.trait_aliases.iter().map(|x| x.clean(cx)));
 
         // determine if we should display the inner contents or
         // the outer `mod` item for the source code.
@@ -1020,20 +1013,6 @@ impl Clean<Item> for doctree::Trait<'_> {
     }
 }
 
-impl Clean<Item> for doctree::TraitAlias<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> Item {
-        Item::from_hir_id_and_parts(
-            self.id,
-            Some(self.name),
-            TraitAliasItem(TraitAlias {
-                generics: self.generics.clean(cx),
-                bounds: self.bounds.clean(cx),
-            }),
-            cx,
-        )
-    }
-}
-
 impl Clean<bool> for hir::IsAuto {
     fn clean(&self, _: &DocContext<'_>) -> bool {
         match *self {
@@ -1777,38 +1756,6 @@ impl Clean<Visibility> for ty::Visibility {
     }
 }
 
-impl Clean<Item> for doctree::Struct<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> Item {
-        Item::from_hir_id_and_parts(
-            self.id,
-            Some(self.name),
-            StructItem(Struct {
-                struct_type: self.struct_type,
-                generics: self.generics.clean(cx),
-                fields: self.fields.clean(cx),
-                fields_stripped: false,
-            }),
-            cx,
-        )
-    }
-}
-
-impl Clean<Item> for doctree::Union<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> Item {
-        Item::from_hir_id_and_parts(
-            self.id,
-            Some(self.name),
-            UnionItem(Union {
-                struct_type: self.struct_type,
-                generics: self.generics.clean(cx),
-                fields: self.fields.clean(cx),
-                fields_stripped: false,
-            }),
-            cx,
-        )
-    }
-}
-
 impl Clean<VariantStruct> for rustc_hir::VariantData<'_> {
     fn clean(&self, cx: &DocContext<'_>) -> VariantStruct {
         VariantStruct {
@@ -1819,21 +1766,6 @@ impl Clean<VariantStruct> for rustc_hir::VariantData<'_> {
     }
 }
 
-impl Clean<Item> for doctree::Enum<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> Item {
-        Item::from_hir_id_and_parts(
-            self.id,
-            Some(self.name),
-            EnumItem(Enum {
-                variants: self.variants.iter().map(|v| v.clean(cx)).collect(),
-                generics: self.generics.clean(cx),
-                variants_stripped: false,
-            }),
-            cx,
-        )
-    }
-}
-
 impl Clean<Item> for doctree::Variant<'_> {
     fn clean(&self, cx: &DocContext<'_>) -> Item {
         let what_rustc_thinks = Item::from_hir_id_and_parts(
@@ -1981,33 +1913,6 @@ impl Clean<String> for Symbol {
     }
 }
 
-impl Clean<Item> for doctree::Typedef<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> Item {
-        let type_ = self.ty.clean(cx);
-        let item_type = type_.def_id().and_then(|did| inline::build_ty(cx, did));
-        Item::from_hir_id_and_parts(
-            self.id,
-            Some(self.name),
-            TypedefItem(Typedef { type_, generics: self.gen.clean(cx), item_type }, false),
-            cx,
-        )
-    }
-}
-
-impl Clean<Item> for doctree::OpaqueTy<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> Item {
-        Item::from_hir_id_and_parts(
-            self.id,
-            Some(self.name),
-            OpaqueTyItem(OpaqueTy {
-                bounds: self.opaque_ty.bounds.clean(cx),
-                generics: self.opaque_ty.generics.clean(cx),
-            }),
-            cx,
-        )
-    }
-}
-
 impl Clean<BareFunctionDecl> for hir::BareFnTy<'_> {
     fn clean(&self, cx: &DocContext<'_>) -> BareFunctionDecl {
         let (generic_params, decl) = enter_impl_trait(cx, || {
@@ -2017,37 +1922,75 @@ impl Clean<BareFunctionDecl> for hir::BareFnTy<'_> {
     }
 }
 
-impl Clean<Item> for doctree::Static<'_> {
+impl Clean<Item> for (&hir::Item<'_>, Option<Ident>) {
     fn clean(&self, cx: &DocContext<'_>) -> Item {
-        debug!("cleaning static {}: {:?}", self.name.clean(cx), self);
-        Item::from_hir_id_and_parts(
-            self.id,
-            Some(self.name),
-            StaticItem(Static {
-                type_: self.type_.clean(cx),
-                mutability: self.mutability,
-                expr: print_const_expr(cx, self.expr),
+        use hir::ItemKind;
+
+        let (item, renamed) = self;
+        let def_id = cx.tcx.hir().local_def_id(item.hir_id).to_def_id();
+        let name = match renamed {
+            Some(ident) => ident.name,
+            None => cx.tcx.hir().name(item.hir_id),
+        };
+        let kind = match item.kind {
+            ItemKind::Static(ty, mutability, body_id) => StaticItem(Static {
+                type_: ty.clean(cx),
+                mutability,
+                expr: print_const_expr(cx, body_id),
             }),
-            cx,
-        )
+            ItemKind::Const(ty, body_id) => ConstantItem(Constant {
+                type_: ty.clean(cx),
+                expr: print_const_expr(cx, body_id),
+                value: print_evaluated_const(cx, def_id),
+                is_literal: is_literal_expr(cx, body_id.hir_id),
+            }),
+            ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
+                bounds: ty.bounds.clean(cx),
+                generics: ty.generics.clean(cx),
+            }),
+            ItemKind::TyAlias(ty, ref generics) => {
+                let rustdoc_ty = ty.clean(cx);
+                let item_type = rustdoc_ty.def_id().and_then(|did| inline::build_ty(cx, did));
+                TypedefItem(
+                    Typedef { type_: rustdoc_ty, generics: generics.clean(cx), item_type },
+                    false,
+                )
+            }
+            ItemKind::Enum(ref def, ref generics) => EnumItem(Enum {
+                variants: def.variants.iter().map(|v| v.clean(cx)).collect(),
+                generics: generics.clean(cx),
+                variants_stripped: false,
+            }),
+            ItemKind::TraitAlias(ref generics, bounds) => TraitAliasItem(TraitAlias {
+                generics: generics.clean(cx),
+                bounds: bounds.clean(cx),
+            }),
+            ItemKind::Union(ref variant_data, ref generics) => UnionItem(Union {
+                struct_type: doctree::struct_type_from_def(&variant_data),
+                generics: generics.clean(cx),
+                fields: variant_data.fields().clean(cx),
+                fields_stripped: false,
+            }),
+            ItemKind::Struct(ref variant_data, ref generics) => StructItem(Struct {
+                struct_type: doctree::struct_type_from_def(&variant_data),
+                generics: generics.clean(cx),
+                fields: variant_data.fields().clean(cx),
+                fields_stripped: false,
+            }),
+            _ => unreachable!("not yet converted"),
+        };
+
+        Item::from_def_id_and_parts(def_id, Some(name), kind, cx)
     }
 }
 
-impl Clean<Item> for doctree::Constant<'_> {
+impl Clean<Item> for hir::Variant<'_> {
     fn clean(&self, cx: &DocContext<'_>) -> Item {
-        let def_id = cx.tcx.hir().local_def_id(self.id).to_def_id();
-
-        Item::from_def_id_and_parts(
-            def_id,
-            Some(self.name),
-            ConstantItem(Constant {
-                type_: self.type_.clean(cx),
-                expr: print_const_expr(cx, self.expr),
-                value: print_evaluated_const(cx, def_id),
-                is_literal: is_literal_expr(cx, self.expr.hir_id),
-            }),
-            cx,
-        )
+        let kind = VariantItem(Variant { kind: self.data.clean(cx) });
+        let what_rustc_thinks =
+            Item::from_hir_id_and_parts(self.id, Some(self.ident.name), kind, cx);
+        // don't show `pub` for variants, which are always public
+        Item { visibility: Inherited, ..what_rustc_thinks }
     }
 }
 
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index bd926219135..d56328cc2aa 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -4,7 +4,7 @@ crate use self::StructType::*;
 
 use rustc_ast as ast;
 use rustc_span::hygiene::MacroKind;
-use rustc_span::{self, Span, Symbol};
+use rustc_span::{self, symbol::Ident, Span, Symbol};
 
 use rustc_hir as hir;
 use rustc_hir::def_id::CrateNum;
@@ -17,22 +17,16 @@ crate struct Module<'hir> {
     crate where_inner: Span,
     crate extern_crates: Vec<ExternCrate<'hir>>,
     crate imports: Vec<Import<'hir>>,
-    crate structs: Vec<Struct<'hir>>,
-    crate unions: Vec<Union<'hir>>,
-    crate enums: Vec<Enum<'hir>>,
     crate fns: Vec<Function<'hir>>,
     crate mods: Vec<Module<'hir>>,
     crate id: hir::HirId,
-    crate typedefs: Vec<Typedef<'hir>>,
-    crate opaque_tys: Vec<OpaqueTy<'hir>>,
-    crate statics: Vec<Static<'hir>>,
-    crate constants: Vec<Constant<'hir>>,
+    // (item, renamed)
+    crate items: Vec<(&'hir hir::Item<'hir>, Option<Ident>)>,
     crate traits: Vec<Trait<'hir>>,
     crate impls: Vec<Impl<'hir>>,
     crate foreigns: Vec<ForeignItem<'hir>>,
     crate macros: Vec<Macro>,
     crate proc_macros: Vec<ProcMacro>,
-    crate trait_aliases: Vec<TraitAlias<'hir>>,
     crate is_crate: bool,
 }
 
@@ -46,21 +40,14 @@ impl Module<'hir> {
             attrs,
             extern_crates: Vec::new(),
             imports: Vec::new(),
-            structs: Vec::new(),
-            unions: Vec::new(),
-            enums: Vec::new(),
             fns: Vec::new(),
             mods: Vec::new(),
-            typedefs: Vec::new(),
-            opaque_tys: Vec::new(),
-            statics: Vec::new(),
-            constants: Vec::new(),
+            items: Vec::new(),
             traits: Vec::new(),
             impls: Vec::new(),
             foreigns: Vec::new(),
             macros: Vec::new(),
             proc_macros: Vec::new(),
-            trait_aliases: Vec::new(),
             is_crate: false,
         }
     }
@@ -76,29 +63,6 @@ crate enum StructType {
     Unit,
 }
 
-crate struct Struct<'hir> {
-    crate id: hir::HirId,
-    crate struct_type: StructType,
-    crate name: Symbol,
-    crate generics: &'hir hir::Generics<'hir>,
-    crate fields: &'hir [hir::StructField<'hir>],
-}
-
-crate struct Union<'hir> {
-    crate id: hir::HirId,
-    crate struct_type: StructType,
-    crate name: Symbol,
-    crate generics: &'hir hir::Generics<'hir>,
-    crate fields: &'hir [hir::StructField<'hir>],
-}
-
-crate struct Enum<'hir> {
-    crate variants: Vec<Variant<'hir>>,
-    crate generics: &'hir hir::Generics<'hir>,
-    crate id: hir::HirId,
-    crate name: Symbol,
-}
-
 crate struct Variant<'hir> {
     crate name: Symbol,
     crate id: hir::HirId,
@@ -114,38 +78,6 @@ crate struct Function<'hir> {
     crate body: hir::BodyId,
 }
 
-crate struct Typedef<'hir> {
-    crate ty: &'hir hir::Ty<'hir>,
-    crate gen: &'hir hir::Generics<'hir>,
-    crate name: Symbol,
-    crate id: hir::HirId,
-}
-
-crate struct OpaqueTy<'hir> {
-    crate opaque_ty: &'hir hir::OpaqueTy<'hir>,
-    crate name: Symbol,
-    crate id: hir::HirId,
-}
-
-#[derive(Debug)]
-crate struct Static<'hir> {
-    crate type_: &'hir hir::Ty<'hir>,
-    crate mutability: hir::Mutability,
-    crate expr: hir::BodyId,
-    crate name: Symbol,
-    crate attrs: &'hir [ast::Attribute],
-    crate vis: &'hir hir::Visibility<'hir>,
-    crate id: hir::HirId,
-    crate span: Span,
-}
-
-crate struct Constant<'hir> {
-    crate type_: &'hir hir::Ty<'hir>,
-    crate expr: hir::BodyId,
-    crate name: Symbol,
-    crate id: hir::HirId,
-}
-
 crate struct Trait<'hir> {
     crate is_auto: hir::IsAuto,
     crate unsafety: hir::Unsafety,
@@ -157,13 +89,6 @@ crate struct Trait<'hir> {
     crate id: hir::HirId,
 }
 
-crate struct TraitAlias<'hir> {
-    crate name: Symbol,
-    crate generics: &'hir hir::Generics<'hir>,
-    crate bounds: &'hir [hir::GenericBound<'hir>],
-    crate id: hir::HirId,
-}
-
 #[derive(Debug)]
 crate struct Impl<'hir> {
     crate unsafety: hir::Unsafety,
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 895414b1d7e..fd09ba04b3d 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -492,7 +492,14 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
             Res::PrimTy(prim) => Some(
                 self.resolve_primitive_associated_item(prim, ns, module_id, item_name, item_str),
             ),
-            Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::TyAlias, did) => {
+            Res::Def(
+                DefKind::Struct
+                | DefKind::Union
+                | DefKind::Enum
+                | DefKind::TyAlias
+                | DefKind::ForeignTy,
+                did,
+            ) => {
                 debug!("looking for associated item named {} for item {:?}", item_name, did);
                 // Checks if item_name belongs to `impl SomeItem`
                 let assoc_item = cx
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 76fae112918..c55e5f7690c 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -82,50 +82,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         module
     }
 
-    fn visit_variant_data(
-        &mut self,
-        item: &'tcx hir::Item<'_>,
-        name: Symbol,
-        sd: &'tcx hir::VariantData<'_>,
-        generics: &'tcx hir::Generics<'_>,
-    ) -> Struct<'tcx> {
-        debug!("visiting struct");
-        let struct_type = struct_type_from_def(&*sd);
-        Struct { id: item.hir_id, struct_type, name, generics, fields: sd.fields() }
-    }
-
-    fn visit_union_data(
-        &mut self,
-        item: &'tcx hir::Item<'_>,
-        name: Symbol,
-        sd: &'tcx hir::VariantData<'_>,
-        generics: &'tcx hir::Generics<'_>,
-    ) -> Union<'tcx> {
-        debug!("visiting union");
-        let struct_type = struct_type_from_def(&*sd);
-        Union { id: item.hir_id, struct_type, name, generics, fields: sd.fields() }
-    }
-
-    fn visit_enum_def(
-        &mut self,
-        it: &'tcx hir::Item<'_>,
-        name: Symbol,
-        def: &'tcx hir::EnumDef<'_>,
-        generics: &'tcx hir::Generics<'_>,
-    ) -> Enum<'tcx> {
-        debug!("visiting enum");
-        Enum {
-            name,
-            variants: def
-                .variants
-                .iter()
-                .map(|v| Variant { name: v.ident.name, id: v.id, def: &v.data })
-                .collect(),
-            generics,
-            id: it.hir_id,
-        }
-    }
-
     fn visit_fn(
         &mut self,
         om: &mut Module<'tcx>,
@@ -414,45 +370,21 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     Some(ident.name),
                 ));
             }
-            hir::ItemKind::Enum(ref ed, ref gen) => {
-                om.enums.push(self.visit_enum_def(item, ident.name, ed, gen))
-            }
-            hir::ItemKind::Struct(ref sd, ref gen) => {
-                om.structs.push(self.visit_variant_data(item, ident.name, sd, gen))
-            }
-            hir::ItemKind::Union(ref sd, ref gen) => {
-                om.unions.push(self.visit_union_data(item, ident.name, sd, gen))
-            }
             hir::ItemKind::Fn(ref sig, ref gen, body) => {
                 self.visit_fn(om, item, ident.name, &sig.decl, sig.header, gen, body)
             }
-            hir::ItemKind::TyAlias(ty, ref gen) => {
-                let t = Typedef { ty, gen, name: ident.name, id: item.hir_id };
-                om.typedefs.push(t);
-            }
-            hir::ItemKind::OpaqueTy(ref opaque_ty) => {
-                let t = OpaqueTy { opaque_ty, name: ident.name, id: item.hir_id };
-                om.opaque_tys.push(t);
-            }
-            hir::ItemKind::Static(type_, mutability, expr) => {
-                let s = Static {
-                    type_,
-                    mutability,
-                    expr,
-                    id: item.hir_id,
-                    name: ident.name,
-                    attrs: &item.attrs,
-                    span: item.span,
-                    vis: &item.vis,
-                };
-                om.statics.push(s);
-            }
-            hir::ItemKind::Const(type_, expr) => {
+            hir::ItemKind::Enum(..)
+            | hir::ItemKind::Struct(..)
+            | hir::ItemKind::Union(..)
+            | hir::ItemKind::TyAlias(..)
+            | hir::ItemKind::OpaqueTy(..)
+            | hir::ItemKind::Static(..)
+            | hir::ItemKind::TraitAlias(..) => om.items.push((item, renamed)),
+            hir::ItemKind::Const(..) => {
                 // Underscore constants do not correspond to a nameable item and
                 // so are never useful in documentation.
                 if ident.name != kw::Underscore {
-                    let s = Constant { type_, expr, id: item.hir_id, name: ident.name };
-                    om.constants.push(s);
+                    om.items.push((item, renamed));
                 }
             }
             hir::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref item_ids) => {
@@ -469,11 +401,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 };
                 om.traits.push(t);
             }
-            hir::ItemKind::TraitAlias(ref generics, ref bounds) => {
-                let t = TraitAlias { name: ident.name, generics, bounds, id: item.hir_id };
-                om.trait_aliases.push(t);
-            }
-
             hir::ItemKind::Impl {
                 unsafety,
                 polarity,
diff --git a/src/test/rustdoc-ui/doc-without-codeblock.stderr b/src/test/rustdoc-ui/doc-without-codeblock.stderr
index f2b2328322a..3372304f44a 100644
--- a/src/test/rustdoc-ui/doc-without-codeblock.stderr
+++ b/src/test/rustdoc-ui/doc-without-codeblock.stderr
@@ -17,12 +17,6 @@ LL | #![deny(missing_doc_code_examples)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing code example in this documentation
-  --> $DIR/doc-without-codeblock.rs:3:1
-   |
-LL | /// Some docs.
-   | ^^^^^^^^^^^^^^
-
-error: missing code example in this documentation
   --> $DIR/doc-without-codeblock.rs:7:1
    |
 LL | /// And then, the princess died.
@@ -34,5 +28,11 @@ error: missing code example in this documentation
 LL |     /// Or maybe not because she saved herself!
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error: missing code example in this documentation
+  --> $DIR/doc-without-codeblock.rs:3:1
+   |
+LL | /// Some docs.
+   | ^^^^^^^^^^^^^^
+
 error: aborting due to 4 previous errors
 
diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.stderr b/src/test/rustdoc-ui/intra-links-ambiguity.stderr
index 21b92a96737..936055da01c 100644
--- a/src/test/rustdoc-ui/intra-links-ambiguity.stderr
+++ b/src/test/rustdoc-ui/intra-links-ambiguity.stderr
@@ -1,14 +1,29 @@
-error: `ambiguous` is both a struct and a function
-  --> $DIR/intra-links-ambiguity.rs:27:6
+error: `true` is both a module and a builtin type
+  --> $DIR/intra-links-ambiguity.rs:38:6
    |
-LL | /// [`ambiguous`] is ambiguous.
-   |      ^^^^^^^^^^^ ambiguous link
+LL | /// [true]
+   |      ^^^^ ambiguous link
    |
 note: the lint level is defined here
   --> $DIR/intra-links-ambiguity.rs:1:9
    |
 LL | #![deny(broken_intra_doc_links)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
+help: to link to the module, prefix with `mod@`
+   |
+LL | /// [mod@true]
+   |      ^^^^^^^^
+help: to link to the builtin type, prefix with `prim@`
+   |
+LL | /// [prim@true]
+   |      ^^^^^^^^^
+
+error: `ambiguous` is both a struct and a function
+  --> $DIR/intra-links-ambiguity.rs:27:6
+   |
+LL | /// [`ambiguous`] is ambiguous.
+   |      ^^^^^^^^^^^ ambiguous link
+   |
 help: to link to the struct, prefix with `struct@`
    |
 LL | /// [`struct@ambiguous`] is ambiguous.
@@ -82,20 +97,5 @@ help: to link to the function, add parentheses
 LL | /// Ambiguous non-implied shortcut link [`foo::bar()`].
    |                                          ^^^^^^^^^^^^
 
-error: `true` is both a module and a builtin type
-  --> $DIR/intra-links-ambiguity.rs:38:6
-   |
-LL | /// [true]
-   |      ^^^^ ambiguous link
-   |
-help: to link to the module, prefix with `mod@`
-   |
-LL | /// [mod@true]
-   |      ^^^^^^^^
-help: to link to the builtin type, prefix with `prim@`
-   |
-LL | /// [prim@true]
-   |      ^^^^^^^^^
-
 error: aborting due to 6 previous errors
 
diff --git a/src/test/rustdoc-ui/intra-links-warning.stderr b/src/test/rustdoc-ui/intra-links-warning.stderr
index 4cdb8bbdde7..bf437a7cf46 100644
--- a/src/test/rustdoc-ui/intra-links-warning.stderr
+++ b/src/test/rustdoc-ui/intra-links-warning.stderr
@@ -36,6 +36,60 @@ warning: unresolved link to `Qux::Z`
 LL |       //! , [Uniooon::X] and [Qux::Z].
    |                               ^^^^^^ no item named `Qux` in scope
 
+warning: unresolved link to `BarA`
+  --> $DIR/intra-links-warning.rs:21:10
+   |
+LL | /// bar [BarA] bar
+   |          ^^^^ no item named `BarA` in scope
+   |
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: unresolved link to `BarB`
+  --> $DIR/intra-links-warning.rs:27:9
+   |
+LL |  * bar [BarB] bar
+   |         ^^^^ no item named `BarB` in scope
+   |
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: unresolved link to `BarC`
+  --> $DIR/intra-links-warning.rs:34:6
+   |
+LL | bar [BarC] bar
+   |      ^^^^ no item named `BarC` in scope
+   |
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: unresolved link to `BarD`
+  --> $DIR/intra-links-warning.rs:45:1
+   |
+LL | #[doc = "Foo\nbar [BarD] bar\nbaz"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the link appears in this line:
+           
+           bar [BarD] bar
+                ^^^^
+   = note: no item named `BarD` in scope
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+warning: unresolved link to `BarF`
+  --> $DIR/intra-links-warning.rs:50:9
+   |
+LL |         #[doc = $f]
+   |         ^^^^^^^^^^^
+...
+LL | f!("Foo\nbar [BarF] bar\nbaz");
+   | ------------------------------- in this macro invocation
+   |
+   = note: the link appears in this line:
+           
+           bar [BarF] bar
+                ^^^^
+   = note: no item named `BarF` in scope
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+   = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
 warning: unresolved link to `Qux:Y`
   --> $DIR/intra-links-warning.rs:14:13
    |
@@ -117,59 +171,5 @@ LL | /// docs [error2]
    |
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-warning: unresolved link to `BarA`
-  --> $DIR/intra-links-warning.rs:21:10
-   |
-LL | /// bar [BarA] bar
-   |          ^^^^ no item named `BarA` in scope
-   |
-   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-
-warning: unresolved link to `BarB`
-  --> $DIR/intra-links-warning.rs:27:9
-   |
-LL |  * bar [BarB] bar
-   |         ^^^^ no item named `BarB` in scope
-   |
-   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-
-warning: unresolved link to `BarC`
-  --> $DIR/intra-links-warning.rs:34:6
-   |
-LL | bar [BarC] bar
-   |      ^^^^ no item named `BarC` in scope
-   |
-   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-
-warning: unresolved link to `BarD`
-  --> $DIR/intra-links-warning.rs:45:1
-   |
-LL | #[doc = "Foo\nbar [BarD] bar\nbaz"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the link appears in this line:
-           
-           bar [BarD] bar
-                ^^^^
-   = note: no item named `BarD` in scope
-   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-
-warning: unresolved link to `BarF`
-  --> $DIR/intra-links-warning.rs:50:9
-   |
-LL |         #[doc = $f]
-   |         ^^^^^^^^^^^
-...
-LL | f!("Foo\nbar [BarF] bar\nbaz");
-   | ------------------------------- in this macro invocation
-   |
-   = note: the link appears in this line:
-           
-           bar [BarF] bar
-                ^^^^
-   = note: no item named `BarF` in scope
-   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-   = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
 warning: 19 warnings emitted
 
diff --git a/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr
index 32756c99e7f..e02ed4a056c 100644
--- a/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr
+++ b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr
@@ -1,8 +1,9 @@
 error: missing code example in this documentation
-  --> $DIR/lint-missing-doc-code-example.rs:49:1
+  --> $DIR/lint-missing-doc-code-example.rs:19:1
    |
-LL | /// Doc
-   | ^^^^^^^
+LL | / mod module1 {
+LL | | }
+   | |_^
    |
 note: the lint level is defined here
   --> $DIR/lint-missing-doc-code-example.rs:2:9
@@ -11,29 +12,28 @@ LL | #![deny(missing_doc_code_examples)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing code example in this documentation
-  --> $DIR/lint-missing-doc-code-example.rs:63:1
+  --> $DIR/lint-missing-doc-code-example.rs:37:3
    |
-LL | /// Doc
-   | ^^^^^^^
+LL |   /// doc
+   |   ^^^^^^^
 
 error: missing code example in this documentation
-  --> $DIR/lint-missing-doc-code-example.rs:56:1
+  --> $DIR/lint-missing-doc-code-example.rs:49:1
    |
 LL | /// Doc
    | ^^^^^^^
 
 error: missing code example in this documentation
-  --> $DIR/lint-missing-doc-code-example.rs:19:1
+  --> $DIR/lint-missing-doc-code-example.rs:56:1
    |
-LL | / mod module1 {
-LL | | }
-   | |_^
+LL | /// Doc
+   | ^^^^^^^
 
 error: missing code example in this documentation
-  --> $DIR/lint-missing-doc-code-example.rs:37:3
+  --> $DIR/lint-missing-doc-code-example.rs:63:1
    |
-LL |   /// doc
-   |   ^^^^^^^
+LL | /// Doc
+   | ^^^^^^^
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/rustdoc/intra-link-extern-type.rs b/src/test/rustdoc/intra-link-extern-type.rs
new file mode 100644
index 00000000000..418e0d91ea7
--- /dev/null
+++ b/src/test/rustdoc/intra-link-extern-type.rs
@@ -0,0 +1,18 @@
+#![feature(extern_types)]
+
+extern {
+    pub type ExternType;
+}
+
+impl ExternType {
+    pub fn f(&self) {
+
+    }
+}
+
+// @has 'intra_link_extern_type/foreigntype.ExternType.html'
+// @has 'intra_link_extern_type/fn.links_to_extern_type.html' \
+// 'href="../intra_link_extern_type/foreigntype.ExternType.html#method.f"'
+/// See also [ExternType::f]
+pub fn links_to_extern_type() {
+}
diff --git a/src/test/rustdoc/redirect-rename.rs b/src/test/rustdoc/redirect-rename.rs
index 7de56080e52..504c0687c8d 100644
--- a/src/test/rustdoc/redirect-rename.rs
+++ b/src/test/rustdoc/redirect-rename.rs
@@ -4,6 +4,10 @@ mod hidden {
     // @has foo/hidden/struct.Foo.html
     // @has - '//p/a' '../../foo/struct.FooBar.html'
     pub struct Foo {}
+    pub union U { a: usize }
+    pub enum Empty {}
+    pub const C: usize = 1;
+    pub static S: usize = 1;
 
     // @has foo/hidden/bar/index.html
     // @has - '//p/a' '../../foo/baz/index.html'
@@ -16,6 +20,14 @@ mod hidden {
 
 // @has foo/struct.FooBar.html
 pub use hidden::Foo as FooBar;
+// @has foo/union.FooU.html
+pub use hidden::U as FooU;
+// @has foo/enum.FooEmpty.html
+pub use hidden::Empty as FooEmpty;
+// @has foo/constant.FooC.html
+pub use hidden::C as FooC;
+// @has foo/static.FooS.html
+pub use hidden::S as FooS;
 
 // @has foo/baz/index.html
 // @has foo/baz/struct.Thing.html
diff --git a/src/test/ui/consts/issue-79137-monomorphic.rs b/src/test/ui/consts/issue-79137-monomorphic.rs
new file mode 100644
index 00000000000..58e0c387ffb
--- /dev/null
+++ b/src/test/ui/consts/issue-79137-monomorphic.rs
@@ -0,0 +1,19 @@
+// check-pass
+
+// Verify that variant count intrinsic can still evaluate for types like `Option<T>`.
+
+#![feature(variant_count)]
+
+pub struct GetVariantCount<T>(T);
+
+impl<T> GetVariantCount<T> {
+    pub const VALUE: usize = std::mem::variant_count::<T>();
+}
+
+const fn check_variant_count<T>() -> bool {
+    matches!(GetVariantCount::<Option<T>>::VALUE, GetVariantCount::<Option<()>>::VALUE)
+}
+
+fn main() {
+    assert!(check_variant_count::<()>());
+}
diff --git a/src/test/ui/consts/issue-79137-toogeneric.rs b/src/test/ui/consts/issue-79137-toogeneric.rs
new file mode 100644
index 00000000000..456035458cf
--- /dev/null
+++ b/src/test/ui/consts/issue-79137-toogeneric.rs
@@ -0,0 +1,19 @@
+// Test that `variant_count` only gets evaluated once the type is concrete enough.
+
+#![feature(variant_count)]
+
+pub struct GetVariantCount<T>(T);
+
+impl<T> GetVariantCount<T> {
+    pub const VALUE: usize = std::mem::variant_count::<T>();
+}
+
+const fn check_variant_count<T>() -> bool {
+    matches!(GetVariantCount::<T>::VALUE, GetVariantCount::<T>::VALUE)
+    //~^ ERROR constant pattern depends on a generic parameter
+    //~| ERROR constant pattern depends on a generic parameter
+}
+
+fn main() {
+    assert!(check_variant_count::<Option<()>>());
+}
diff --git a/src/test/ui/consts/issue-79137-toogeneric.stderr b/src/test/ui/consts/issue-79137-toogeneric.stderr
new file mode 100644
index 00000000000..579e6aa09bd
--- /dev/null
+++ b/src/test/ui/consts/issue-79137-toogeneric.stderr
@@ -0,0 +1,14 @@
+error: constant pattern depends on a generic parameter
+  --> $DIR/issue-79137-toogeneric.rs:12:43
+   |
+LL |     matches!(GetVariantCount::<T>::VALUE, GetVariantCount::<T>::VALUE)
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: constant pattern depends on a generic parameter
+  --> $DIR/issue-79137-toogeneric.rs:12:43
+   |
+LL |     matches!(GetVariantCount::<T>::VALUE, GetVariantCount::<T>::VALUE)
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/mir/mir-inlining/array-clone-with-generic-size.rs b/src/test/ui/mir/mir-inlining/array-clone-with-generic-size.rs
new file mode 100644
index 00000000000..8a96303e6b9
--- /dev/null
+++ b/src/test/ui/mir/mir-inlining/array-clone-with-generic-size.rs
@@ -0,0 +1,13 @@
+// Checks that we can build a clone shim for array with generic size.
+// Regression test for issue #79269.
+//
+// build-pass
+// compile-flags: -Zmir-opt-level=2 -Zvalidate-mir
+#![feature(min_const_generics)]
+
+#[derive(Clone)]
+struct Array<T, const N: usize>([T; N]);
+
+fn main() {
+    let _ = Array([0u32, 1u32, 2u32]).clone();
+}