about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-11-24 12:27:30 +0000
committerbors <bors@rust-lang.org>2020-11-24 12:27:30 +0000
commit53d19b37c514246acab020eaba9527cb97c421cf (patch)
tree657b3ff7ff74baa3b855bfee35724114b9fb2364
parent6331023708aabef7fbd4ca502feb48c3afc83b41 (diff)
parentf049b0be9695cc87938436b50b982fc6013f8344 (diff)
downloadrust-53d19b37c514246acab020eaba9527cb97c421cf.tar.gz
rust-53d19b37c514246acab020eaba9527cb97c421cf.zip
Auto merge of #79377 - jonas-schievink:rollup-ye81i66, r=jonas-schievink
Rollup of 10 pull requests

Successful merges:

 - #76858 (Add exploit mitigations chapter to the rustc book)
 - #79310 (Make `fold_item_recur` non-nullable)
 - #79312 (Get rid of `doctree::Impl`)
 - #79321 (Accept '!' in intra-doc links)
 - #79346 (Allow using `-Z fewer-names=no` to retain value names)
 - #79351 (Fix typo in `keyword` docs for traits)
 - #79354 (BTreeMap: cut out the ceremony around BoxedNode)
 - #79358 (BTreeMap/BTreeSet: make public doc more consistent)
 - #79367 (Allow disabling TrapUnreachable via -Ztrap-unreachable=no)
 - #79374 (Add note to use nightly when using expr in const generics)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs3
-rw-r--r--compiler/rustc_interface/src/tests.rs3
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs1
-rw-r--r--compiler/rustc_session/src/options.rs4
-rw-r--r--compiler/rustc_session/src/session.rs15
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs2
-rw-r--r--library/alloc/src/collections/btree/map.rs4
-rw-r--r--library/alloc/src/collections/btree/node.rs50
-rw-r--r--library/alloc/src/collections/btree/set.rs6
-rw-r--r--library/std/src/keyword_docs.rs2
-rw-r--r--src/doc/rustc/src/SUMMARY.md1
-rw-r--r--src/doc/rustc/src/exploit-mitigations.md693
-rw-r--r--src/doc/rustc/src/images/image1.pngbin0 -> 15293 bytes
-rw-r--r--src/doc/rustc/src/images/image2.pngbin0 -> 28772 bytes
-rw-r--r--src/doc/rustc/src/images/image3.pngbin0 -> 72412 bytes
-rw-r--r--src/etc/gdb_providers.py12
-rw-r--r--src/librustdoc/clean/mod.rs102
-rw-r--r--src/librustdoc/core.rs16
-rw-r--r--src/librustdoc/doctree.rs18
-rw-r--r--src/librustdoc/fold.rs13
-rw-r--r--src/librustdoc/formats/cache.rs77
-rw-r--r--src/librustdoc/html/sources.rs2
-rw-r--r--src/librustdoc/passes/calculate_doc_coverage.rs2
-rw-r--r--src/librustdoc/passes/check_code_block_syntax.rs2
-rw-r--r--src/librustdoc/passes/collapse_docs.rs2
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs8
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs4
-rw-r--r--src/librustdoc/passes/doc_test_lints.rs2
-rw-r--r--src/librustdoc/passes/html_tags.rs4
-rw-r--r--src/librustdoc/passes/non_autolinks.rs4
-rw-r--r--src/librustdoc/passes/propagate_doc_cfg.rs2
-rw-r--r--src/librustdoc/passes/strip_hidden.rs4
-rw-r--r--src/librustdoc/passes/stripper.rs16
-rw-r--r--src/librustdoc/passes/unindent_comments.rs2
-rw-r--r--src/librustdoc/visit_ast.rs30
-rw-r--r--src/test/codegen/fewer-names.rs20
-rw-r--r--src/test/rustdoc-ui/intra-link-errors.stderr18
-rw-r--r--src/test/rustdoc/intra-doc-link-generic-params.rs3
-rw-r--r--src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr4
-rw-r--r--src/test/ui/const-generics/const-arg-in-const-arg.min.stderr7
-rw-r--r--src/test/ui/const-generics/const-argument-if-length.min.stderr1
-rw-r--r--src/test/ui/const-generics/const-param-before-other-params.min.stderr4
-rw-r--r--src/test/ui/const-generics/const-param-elided-lifetime.min.stderr10
-rw-r--r--src/test/ui/const-generics/const-param-type-depends-on-const-param.min.stderr4
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr1
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr2
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr1
-rw-r--r--src/test/ui/const-generics/different_byref.min.stderr2
-rw-r--r--src/test/ui/const-generics/forbid-non-structural_match-types.min.stderr4
-rw-r--r--src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr2
-rw-r--r--src/test/ui/const-generics/generic-sum-in-array-length.min.stderr2
-rw-r--r--src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr3
-rw-r--r--src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr2
-rw-r--r--src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.min.stderr2
-rw-r--r--src/test/ui/const-generics/issue-67375.min.stderr1
-rw-r--r--src/test/ui/const-generics/issue-67945-1.min.stderr2
-rw-r--r--src/test/ui/const-generics/issue-67945-2.min.stderr2
-rw-r--r--src/test/ui/const-generics/issues/issue-61747.min.stderr1
-rw-r--r--src/test/ui/const-generics/issues/issue-61935.min.stderr1
-rw-r--r--src/test/ui/const-generics/issues/issue-62220.min.stderr1
-rw-r--r--src/test/ui/const-generics/issues/issue-62456.min.stderr1
-rw-r--r--src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr2
-rw-r--r--src/test/ui/const-generics/issues/issue-62878.min.stderr2
-rw-r--r--src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr2
-rw-r--r--src/test/ui/const-generics/issues/issue-64494.min.stderr2
-rw-r--r--src/test/ui/const-generics/issues/issue-66205.min.stderr1
-rw-r--r--src/test/ui/const-generics/issues/issue-68366.min.stderr1
-rw-r--r--src/test/ui/const-generics/issues/issue-68615-adt.min.stderr2
-rw-r--r--src/test/ui/const-generics/issues/issue-68615-array.min.stderr2
-rw-r--r--src/test/ui/const-generics/issues/issue-68977.min.stderr2
-rw-r--r--src/test/ui/const-generics/issues/issue-71169.min.stderr2
-rw-r--r--src/test/ui/const-generics/issues/issue-72787.min.stderr4
-rw-r--r--src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr1
-rw-r--r--src/test/ui/const-generics/issues/issue-73491.min.stderr2
-rw-r--r--src/test/ui/const-generics/issues/issue-74101.min.stderr4
-rw-r--r--src/test/ui/const-generics/issues/issue-74255.min.stderr2
-rw-r--r--src/test/ui/const-generics/issues/issue-74950.min.stderr10
-rw-r--r--src/test/ui/const-generics/issues/issue-75047.min.stderr2
-rw-r--r--src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr2
-rw-r--r--src/test/ui/const-generics/macro_rules-braces.min.stderr4
-rw-r--r--src/test/ui/const-generics/min_const_generics/complex-expression.stderr7
-rw-r--r--src/test/ui/const-generics/min_const_generics/complex-types.stderr14
-rw-r--r--src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr1
-rw-r--r--src/test/ui/const-generics/min_const_generics/static-reference-array-const-param.stderr2
-rw-r--r--src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.stderr2
-rw-r--r--src/test/ui/const-generics/nested-type.min.stderr2
-rw-r--r--src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr1
-rw-r--r--src/test/ui/const-generics/slice-const-param-mismatch.min.stderr4
-rw-r--r--src/test/ui/const-generics/slice-const-param.min.stderr4
-rw-r--r--src/test/ui/const-generics/std/const-generics-range.min.stderr12
-rw-r--r--src/test/ui/const-generics/type-dependent/issue-71348.min.stderr4
-rw-r--r--src/test/ui/const-generics/wf-misc.min.stderr2
92 files changed, 999 insertions, 312 deletions
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 6f956c3bcc1..7407dfc455d 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -152,7 +152,8 @@ pub fn target_machine_factory(
     let features = features.join(",");
     let features = CString::new(features).unwrap();
     let abi = SmallCStr::new(&sess.target.llvm_abiname);
-    let trap_unreachable = sess.target.trap_unreachable;
+    let trap_unreachable =
+        sess.opts.debugging_opts.trap_unreachable.unwrap_or(sess.target.trap_unreachable);
     let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes;
 
     let asm_comments = sess.asm_comments();
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 1fc2d281e79..92262050b8c 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -547,7 +547,7 @@ fn test_debugging_options_tracking_hash() {
     tracked!(debug_macros, true);
     tracked!(dep_info_omit_d_target, true);
     tracked!(dual_proc_macros, true);
-    tracked!(fewer_names, true);
+    tracked!(fewer_names, Some(true));
     tracked!(force_overflow_checks, Some(true));
     tracked!(force_unstable_if_unmarked, true);
     tracked!(fuel, Some(("abc".to_string(), 99)));
@@ -592,6 +592,7 @@ fn test_debugging_options_tracking_hash() {
     tracked!(thinlto, Some(true));
     tracked!(tune_cpu, Some(String::from("abc")));
     tracked!(tls_model, Some(TlsModel::GeneralDynamic));
+    tracked!(trap_unreachable, Some(false));
     tracked!(treat_err_as_bug, Some(1));
     tracked!(unleash_the_miri_inside_of_you, true);
     tracked!(use_ctors_section, Some(true));
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 67491b5bf7e..a0d5b61e8bd 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -481,6 +481,7 @@ impl<'a> Resolver<'a> {
                         name
                     ));
                 }
+                err.help("use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions");
 
                 err
             }
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 1cd3d11e321..731bbf029fa 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -900,7 +900,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "emits a future-incompatibility report for lints (RFC 2834)"),
     emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
         "emit a section containing stack size metadata (default: no)"),
-    fewer_names: bool = (false, parse_bool, [TRACKED],
+    fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \
         (default: no)"),
     force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
@@ -1113,6 +1113,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "choose the TLS model to use (`rustc --print tls-models` for details)"),
     trace_macros: bool = (false, parse_bool, [UNTRACKED],
         "for every macro invocation, print its name and arguments (default: no)"),
+    trap_unreachable: Option<bool> = (None, parse_opt_bool, [TRACKED],
+        "generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)"),
     treat_err_as_bug: Option<usize> = (None, parse_treat_err_as_bug, [TRACKED],
         "treat error number `val` that occurs as bug"),
     trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED],
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 419d1447764..5dddf0eb72e 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -734,12 +734,15 @@ impl Session {
         self.opts.cg.panic.unwrap_or(self.target.panic_strategy)
     }
     pub fn fewer_names(&self) -> bool {
-        let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly)
-            || self.opts.output_types.contains_key(&OutputType::Bitcode)
-            // AddressSanitizer and MemorySanitizer use alloca name when reporting an issue.
-            || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY);
-
-        self.opts.debugging_opts.fewer_names || !more_names
+        if let Some(fewer_names) = self.opts.debugging_opts.fewer_names {
+            fewer_names
+        } else {
+            let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly)
+                || self.opts.output_types.contains_key(&OutputType::Bitcode)
+                // AddressSanitizer and MemorySanitizer use alloca name when reporting an issue.
+                || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY);
+            !more_names
+        }
     }
 
     pub fn unstable_options(&self) -> bool {
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 5dffe5107b5..aeca801a4ee 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -329,7 +329,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
                             ),
                         )
                         .note("the only supported types are integers, `bool` and `char`")
-                        .note("more complex types are supported with `#[feature(const_generics)]`")
+                        .help("more complex types are supported with `#[feature(const_generics)]`")
                         .emit()
                 }
             };
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index eb32cef24a1..bd2ad257402 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -458,7 +458,7 @@ impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for RangeMut<'_, K, V> {
 }
 
 impl<K: Ord, V> BTreeMap<K, V> {
-    /// Makes a new empty BTreeMap.
+    /// Makes a new, empty `BTreeMap`.
     ///
     /// Does not allocate anything on its own.
     ///
@@ -1924,7 +1924,7 @@ impl<K: Hash, V: Hash> Hash for BTreeMap<K, V> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<K: Ord, V> Default for BTreeMap<K, V> {
-    /// Creates an empty `BTreeMap<K, V>`.
+    /// Creates an empty `BTreeMap`.
     fn default() -> BTreeMap<K, V> {
         BTreeMap::new()
     }
diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs
index e3e555a72de..6a8be441513 100644
--- a/library/alloc/src/collections/btree/node.rs
+++ b/library/alloc/src/collections/btree/node.rs
@@ -112,20 +112,8 @@ impl<K, V> InternalNode<K, V> {
 ///
 /// However, `BoxedNode` contains no information as to which of the two types
 /// of nodes it actually contains, and, partially due to this lack of information,
-/// has no destructor.
-struct BoxedNode<K, V> {
-    ptr: NonNull<LeafNode<K, V>>,
-}
-
-impl<K, V> BoxedNode<K, V> {
-    fn from_owned(ptr: NonNull<LeafNode<K, V>>) -> Self {
-        BoxedNode { ptr }
-    }
-
-    fn as_ptr(&self) -> NonNull<LeafNode<K, V>> {
-        self.ptr
-    }
-}
+/// is not a separate type and has no destructor.
+type BoxedNode<K, V> = NonNull<LeafNode<K, V>>;
 
 /// An owned tree.
 ///
@@ -168,11 +156,6 @@ impl<K, V, Type> NodeRef<marker::Owned, K, V, Type> {
     pub fn borrow_valmut(&mut self) -> NodeRef<marker::ValMut<'_>, K, V, Type> {
         NodeRef { height: self.height, node: self.node, _marker: PhantomData }
     }
-
-    /// Packs the reference, aware of type and height, into a type-agnostic pointer.
-    fn into_boxed_node(self) -> BoxedNode<K, V> {
-        BoxedNode::from_owned(self.node)
-    }
 }
 
 impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
@@ -181,7 +164,7 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
     /// and is the opposite of `pop_internal_level`.
     pub fn push_internal_level(&mut self) -> NodeRef<marker::Mut<'_>, K, V, marker::Internal> {
         let mut new_node = Box::new(unsafe { InternalNode::new() });
-        new_node.edges[0].write(BoxedNode::from_owned(self.node));
+        new_node.edges[0].write(self.node);
         let mut new_root = NodeRef::from_new_internal(new_node, self.height + 1);
         new_root.borrow_mut().first_edge().correct_parent_link();
         *self = new_root.forget_type();
@@ -288,13 +271,6 @@ unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef<marker::Mut<'
 unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef<marker::ValMut<'a>, K, V, Type> {}
 unsafe impl<K: Send, V: Send, Type> Send for NodeRef<marker::Owned, K, V, Type> {}
 
-impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
-    /// Unpack a node reference that was packed by `Root::into_boxed_node`.
-    fn from_boxed_node(boxed_node: BoxedNode<K, V>, height: usize) -> Self {
-        NodeRef { height, node: boxed_node.as_ptr(), _marker: PhantomData }
-    }
-}
-
 impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Internal> {
     /// Unpack a node reference that was packed as `NodeRef::parent`.
     fn from_internal(node: NonNull<InternalNode<K, V>>, height: usize) -> Self {
@@ -695,7 +671,7 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
         unsafe {
             self.reborrow_mut().into_key_area_mut_at(idx).write(key);
             self.reborrow_mut().into_val_area_mut_at(idx).write(val);
-            self.reborrow_mut().into_edge_area_mut_at(idx + 1).write(edge.into_boxed_node());
+            self.reborrow_mut().into_edge_area_mut_at(idx + 1).write(edge.node);
             Handle::new_edge(self.reborrow_mut(), idx + 1).correct_parent_link();
         }
     }
@@ -710,7 +686,7 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
             *self.reborrow_mut().into_len_mut() += 1;
             slice_insert(self.reborrow_mut().into_key_area_slice(), 0, key);
             slice_insert(self.reborrow_mut().into_val_area_slice(), 0, val);
-            slice_insert(self.reborrow_mut().into_edge_area_slice(), 0, edge.into_boxed_node());
+            slice_insert(self.reborrow_mut().into_edge_area_slice(), 0, edge.node);
         }
 
         self.correct_all_childrens_parent_links();
@@ -732,8 +708,8 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
             let edge = match self.reborrow_mut().force() {
                 ForceResult::Leaf(_) => None,
                 ForceResult::Internal(internal) => {
-                    let boxed_node = ptr::read(internal.reborrow().edge_at(idx + 1));
-                    let mut edge = Root::from_boxed_node(boxed_node, internal.height - 1);
+                    let node = ptr::read(internal.reborrow().edge_at(idx + 1));
+                    let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData };
                     // In practice, clearing the parent is a waste of time, because we will
                     // insert the node elsewhere and set its parent link again.
                     edge.borrow_mut().clear_parent_link();
@@ -760,9 +736,8 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
             let edge = match self.reborrow_mut().force() {
                 ForceResult::Leaf(_) => None,
                 ForceResult::Internal(mut internal) => {
-                    let boxed_node =
-                        slice_remove(internal.reborrow_mut().into_edge_area_slice(), 0);
-                    let mut edge = Root::from_boxed_node(boxed_node, internal.height - 1);
+                    let node = slice_remove(internal.reborrow_mut().into_edge_area_slice(), 0);
+                    let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData };
                     // In practice, clearing the parent is a waste of time, because we will
                     // insert the node elsewhere and set its parent link again.
                     edge.borrow_mut().clear_parent_link();
@@ -1041,12 +1016,11 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
         debug_assert!(self.node.len() < CAPACITY);
         debug_assert!(edge.height == self.node.height - 1);
 
-        let boxed_node = edge.into_boxed_node();
         unsafe {
             *self.node.reborrow_mut().into_len_mut() += 1;
             slice_insert(self.node.reborrow_mut().into_key_area_slice(), self.idx, key);
             slice_insert(self.node.reborrow_mut().into_val_area_slice(), self.idx, val);
-            slice_insert(self.node.reborrow_mut().into_edge_area_slice(), self.idx + 1, boxed_node);
+            slice_insert(self.node.reborrow_mut().into_edge_area_slice(), self.idx + 1, edge.node);
 
             self.node.correct_childrens_parent_links((self.idx + 1)..=self.node.len());
         }
@@ -1135,8 +1109,8 @@ impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Internal>, marke
         // reference (Rust issue #73987) and invalidate any other references
         // to or inside the array, should any be around.
         let parent_ptr = NodeRef::as_internal_ptr(&self.node);
-        let boxed_node = unsafe { (*parent_ptr).edges.get_unchecked(self.idx).assume_init_read() };
-        NodeRef::from_boxed_node(boxed_node, self.node.height - 1)
+        let node = unsafe { (*parent_ptr).edges.get_unchecked(self.idx).assume_init_read() };
+        NodeRef { node, height: self.node.height - 1, _marker: PhantomData }
     }
 }
 
diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs
index 1a807100653..f4046e87b99 100644
--- a/library/alloc/src/collections/btree/set.rs
+++ b/library/alloc/src/collections/btree/set.rs
@@ -220,7 +220,9 @@ impl<T: fmt::Debug> fmt::Debug for Union<'_, T> {
 const ITER_PERFORMANCE_TIPPING_SIZE_DIFF: usize = 16;
 
 impl<T: Ord> BTreeSet<T> {
-    /// Makes a new `BTreeSet` with a reasonable choice of B.
+    /// Makes a new, empty `BTreeSet`.
+    ///
+    /// Does not allocate anything on its own.
     ///
     /// # Examples
     ///
@@ -1121,7 +1123,7 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BTreeSet<T> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Ord> Default for BTreeSet<T> {
-    /// Makes an empty `BTreeSet<T>` with a reasonable choice of B.
+    /// Creates an empty `BTreeSet`.
     fn default() -> BTreeSet<T> {
         BTreeSet::new()
     }
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index b990b785703..80b74a9ba9b 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -1739,7 +1739,7 @@ mod super_keyword {}
 ///
 /// # Differences between the 2015 and 2018 editions
 ///
-/// In the 2015 edition parameters pattern where not needed for traits:
+/// In the 2015 edition the parameters pattern was not needed for traits:
 ///
 /// ```rust,edition2015
 /// trait Tr {
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 57013e9194b..dd198615736 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -18,4 +18,5 @@
     - [Known Issues](targets/known-issues.md)
 - [Profile-guided Optimization](profile-guided-optimization.md)
 - [Linker-plugin based LTO](linker-plugin-lto.md)
+- [Exploit Mitigations](exploit-mitigations.md)
 - [Contributing to `rustc`](contributing.md)
diff --git a/src/doc/rustc/src/exploit-mitigations.md b/src/doc/rustc/src/exploit-mitigations.md
new file mode 100644
index 00000000000..44d5d9564f2
--- /dev/null
+++ b/src/doc/rustc/src/exploit-mitigations.md
@@ -0,0 +1,693 @@
+# Exploit Mitigations
+
+This chapter documents the exploit mitigations supported by the Rust
+compiler, and is by no means an extensive survey of the Rust programming
+language’s security features.
+
+This chapter is for software engineers working with the Rust programming
+language, and assumes prior knowledge of the Rust programming language and
+its toolchain.
+
+
+## Introduction
+
+The Rust programming language provides memory[1] and thread[2] safety
+guarantees via its ownership[3], references and borrowing[4], and slice
+types[5] features. However, Unsafe Rust[6] introduces unsafe blocks, unsafe
+functions and methods, unsafe traits, and new types that are not subject to
+the borrowing rules.
+
+Parts of the Rust standard library are implemented as safe abstractions over
+unsafe code (and historically have been vulnerable to memory corruption[7]).
+Furthermore, the Rust code and documentation encourage creating safe
+abstractions over unsafe code. This can cause a false sense of security if
+unsafe code is not properly reviewed and tested.
+
+Unsafe Rust introduces features that do not provide the same memory and
+thread safety guarantees. This causes programs or libraries to be
+susceptible to memory corruption (CWE-119)[8] and concurrency issues
+(CWE-557)[9]. Modern C and C++ compilers provide exploit mitigations to
+increase the difficulty to exploit vulnerabilities resulting from these
+issues. Therefore, the Rust compiler must also support these exploit
+mitigations in order to mitigate vulnerabilities resulting from the use of
+Unsafe Rust. This chapter documents these exploit mitigations and how they
+apply to Rust.
+
+This chapter does not discuss the effectiveness of these exploit mitigations
+as they vary greatly depending on several factors besides their design and
+implementation, but rather describe what they do, so their effectiveness can
+be understood within a given context.
+
+
+## Exploit mitigations
+
+This section documents the exploit mitigations applicable to the Rust
+compiler when building programs for the Linux operating system on the AMD64
+architecture and equivalent.<sup id="fnref:1" role="doc-noteref"><a
+href="#fn:1" class="footnote">1</a></sup>
+
+The Rust Programming Language currently has no specification. The Rust
+compiler (i.e., rustc) is the language reference implementation. All
+references to “the Rust compiler” in this chapter refer to the language
+reference implementation.
+
+Table I \
+Summary of exploit mitigations supported by the Rust compiler when building
+programs for the Linux operating system on the AMD64 architecture and
+equivalent.
+<table class="table">
+  <tr>
+   <td><strong>Exploit mitigation</strong>
+   </td>
+   <td><strong>Supported and enabled by default</strong>
+   </td>
+   <td><strong>Since</strong>
+   </td>
+  </tr>
+  <tr>
+   <td>Position-independent executable
+   </td>
+   <td>Yes
+   </td>
+   <td>0.12.0 (2014-10-09)
+   </td>
+  </tr>
+  <tr>
+   <td>Integer overflow checks
+   </td>
+   <td>Yes (enabled when debug assertions are enabled, and disabled when debug assertions are disabled)
+   </td>
+   <td>1.1.0 (2015-06-25)
+   </td>
+  </tr>
+  <tr>
+   <td>Non-executable memory regions
+   </td>
+   <td>Yes
+   </td>
+   <td>1.8.0 (2016-04-14)
+   </td>
+  </tr>
+  <tr>
+   <td>Stack clashing protection
+   </td>
+   <td>Yes
+   </td>
+   <td>1.20.0 (2017-08-31)
+   </td>
+  </tr>
+  <tr>
+   <td>Read-only relocations and immediate binding
+   </td>
+   <td>Yes
+   </td>
+   <td>1.21.0 (2017-10-12)
+   </td>
+  </tr>
+  <tr>
+   <td>Heap corruption protection
+   </td>
+   <td>Yes
+   </td>
+   <td>1.32.0 (2019-01-17) (via operating system default or specified allocator)
+   </td>
+  </tr>
+  <tr>
+   <td>Stack smashing protection
+   </td>
+   <td>No
+   </td>
+   <td>
+   </td>
+  </tr>
+  <tr>
+   <td>Forward-edge control flow protection
+   </td>
+   <td>No
+   </td>
+   <td>
+   </td>
+  </tr>
+  <tr>
+   <td>Backward-edge control flow protection (e.g., shadow and safe stack)
+   </td>
+   <td>No
+   </td>
+   <td>
+   </td>
+  </tr>
+</table>
+
+<small id="fn:1">1\. See
+<https://github.com/rust-lang/rust/tree/master/compiler/rustc_target/src/spec>
+for a list of targets and their default options. <a href="#fnref:1"
+class="reversefootnote" role="doc-backlink">↩</a></small>
+
+
+### Position-independent executable
+
+Position-independent executable increases the difficulty of the use of code
+reuse exploitation techniques, such as return-oriented programming (ROP) and
+variants, by generating position-independent code for the executable, and
+instructing the dynamic linker to load it similarly to a shared object at a
+random load address, thus also benefiting from address-space layout
+randomization (ASLR). This is also referred to as “full ASLR”.
+
+The Rust compiler supports position-independent executable, and enables it
+by default since version 0.12.0 (2014-10-09)[10]–[13].
+
+```text
+$ readelf -h target/release/hello-rust | grep Type:
+  Type:                              DYN (Shared object file)
+```
+Fig. 1. Checking if an executable is a position-independent executable.
+
+An executable with an object type of `ET_DYN` (i.e., shared object) and not
+`ET_EXEC` (i.e., executable) is a position-independent executable (see Fig.
+1).
+
+
+### Integer overflow checks
+
+Integer overflow checks protects programs from undefined and unintended
+behavior (which may cause vulnerabilities) by checking for results of signed
+and unsigned integer computations that cannot be represented in their type,
+resulting in an overflow or wraparound.
+
+The Rust compiler supports integer overflow checks, and enables it when
+debug assertions are enabled since version 1.1.0 (2015-06-25)[14]–[20].
+
+```compile_fail
+fn main() {
+    let u: u8 = 255;
+    println!("u: {}", u + 1);
+}
+```
+Fig. 2. hello-rust-integer program.
+
+```text
+$ cargo run
+   Compiling hello-rust-integer v0.1.0 (/home/rcvalle/hello-rust-integer)
+    Finished dev [unoptimized + debuginfo] target(s) in 0.23s
+     Running `target/debug/hello-rust-integer`
+thread 'main' panicked at 'attempt to add with overflow', src/main.rs:3:23
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
+```
+Fig. 3. Build and execution of hello-rust-integer with debug assertions
+enabled.
+
+```text
+$ cargo run --release
+   Compiling hello-rust-integer v0.1.0 (/home/rcvalle/hello-rust-integer)
+    Finished release [optimized] target(s) in 0.23s
+     Running `target/release/hello-rust-integer`
+u: 0
+```
+Fig. 4. Build and execution of hello-rust-integer with debug assertions
+disabled.
+
+Integer overflow checks are enabled when debug assertions are enabled (see
+Fig. 3), and disabled when debug assertions are disabled (see Fig. 4). To
+enable integer overflow checks independently, use the option to control
+integer overflow checks, scoped attributes, or explicit checking methods
+such as `checked_add`<sup id="fnref:2" role="doc-noteref"><a href="#fn:2"
+class="footnote">2</a></sup>.
+
+It is recommended that explicit wrapping methods such as `wrapping_add` be
+used when wrapping semantics are intended, and that explicit checking and
+wrapping methods always be used when using Unsafe Rust.
+
+<small id="fn:2">2\. See <https://doc.rust-lang.org/std/primitive.u32.html>
+for more information on the checked, overflowing, saturating, and wrapping
+methods (using u32 as an example). <a href="#fnref:2"
+class="reversefootnote" role="doc-backlink">↩</a></small>
+
+
+### Non-executable memory regions
+
+Non-executable memory regions increase the difficulty of exploitation by
+limiting the memory regions that can be used to execute arbitrary code. Most
+modern processors provide support for the operating system to mark memory
+regions as non executable, but it was previously emulated by software, such
+as in grsecurity/PaX's
+[PAGEEXEC](https://pax.grsecurity.net/docs/pageexec.txt) and
+[SEGMEXEC](https://pax.grsecurity.net/docs/segmexec.txt), on processors that
+did not provide support for it. This is also known as “No Execute (NX) Bit”,
+“Execute Disable (XD) Bit”, “Execute Never (XN) Bit”, and others.
+
+The Rust compiler supports non-executable memory regions, and enables it by
+default since its initial release, version 0.1 (2012-01-20)[21], [22], but
+has regressed since then[23]–[25], and enforced by default since version
+1.8.0 (2016-04-14)[25].
+
+```text
+$ readelf -l target/release/hello-rust | grep -A 1 GNU_STACK
+  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
+                 0x0000000000000000 0x0000000000000000  RW     0x10
+```
+Fig. 5. Checking if non-executable memory regions are enabled for a given
+binary.
+
+The presence of an element of type `PT_GNU_STACK` in the program header
+table with the `PF_X` (i.e., executable) flag unset indicates non-executable
+memory regions<sup id="fnref:3" role="doc-noteref"><a href="#fn:3"
+class="footnote">3</a></sup> are enabled for a given binary (see Fig. 5).
+Conversely, the presence of an element of type `PT_GNU_STACK` in the program
+header table with the `PF_X` flag set or the absence of an element of type
+`PT_GNU_STACK` in the program header table indicates non-executable memory
+regions are not enabled for a given binary.
+
+<small id="fn:3">3\. See the Appendix section for more information on why it
+affects other memory regions besides the stack. <a href="#fnref:3"
+class="reversefootnote" role="doc-backlink">↩</a></small>
+
+
+### Stack clashing protection
+
+Stack clashing protection protects the stack from overlapping with another
+memory region—allowing arbitrary data in both to be overwritten using each
+other—by reading from the stack pages as the stack grows to cause a page
+fault when attempting to read from the guard page/region. This is also
+referred to as “stack probes” or “stack probing”.
+
+The Rust compiler supports stack clashing protection via stack probing, and
+enables it by default since version 1.20.0 (2017-08-31)[26]–[29].
+
+![Screenshot of IDA Pro listing cross references to __rust_probestack in hello-rust.](images/image1.png "Cross references to __rust_probestack in hello-rust.")
+Fig. 6. IDA Pro listing cross references to `__rust_probestack` in
+hello-rust.
+
+```rust
+fn hello() {
+    println!("Hello, world!");
+}
+
+fn main() {
+    let _: [u64; 1024] = [0; 1024];
+    hello();
+}
+```
+Fig 7. Modified hello-rust.
+
+![Screenshot of IDA Pro listing cross references to __rust_probestack in modified hello-rust.](images/image2.png "Cross references to __rust_probestack in modified hello-rust.")
+Fig. 8. IDA Pro listing cross references to `__rust_probestack` in modified
+hello-rust.
+
+To check if stack clashing protection is enabled for a given binary, search
+for cross references to `__rust_probestack`. The `__rust_probestack` is
+called in the prologue of functions whose stack size is larger than a page
+size (see Fig. 6), and can be forced for illustration purposes by modifying
+the hello-rust example as seen in Fig. 7 and Fig. 8.
+
+
+### Read-only relocations and immediate binding
+
+**Read-only relocations** protect segments containing relocations and
+relocation information (i.e., `.init_array`, `.fini_array`, `.dynamic`, and
+`.got`) from being overwritten by marking these segments read only. This is
+also referred to as “partial RELRO”.
+
+The Rust compiler supports read-only relocations, and enables it by default
+since version 1.21.0 (2017-10-12)[30], [31].
+
+```text
+$ readelf -l target/release/hello-rust | grep GNU_RELRO
+  GNU_RELRO      0x000000000002ee00 0x000000000002fe00 0x000000000002fe00
+```
+Fig. 9. Checking if read-only relocations is enabled for a given binary.
+
+The presence of an element of type `PT_GNU_RELRO` in the program header
+table indicates read-only relocations are enabled for a given binary (see
+Fig. 9). Conversely, the absence of an element of type `PT_GNU_RELRO` in the
+program header table indicates read-only relocations are not enabled for a
+given binary.
+
+**Immediate binding** protects additional segments containing relocations
+(i.e., `.got.plt`) from being overwritten by instructing the dynamic linker
+to perform all relocations before transferring control to the program during
+startup, so all segments containing relocations can be marked read only
+(when combined with read-only relocations). This is also referred to as
+“full RELRO”.
+
+The Rust compiler supports immediate binding, and enables it by default
+since version 1.21.0 (2017-10-12)[30], [31].
+
+```text
+$ readelf -d target/release/hello-rust | grep BIND_NOW
+ 0x000000000000001e (FLAGS)              BIND_NOW
+```
+Fig. 10. Checking if immediate binding is enabled for a given binary.
+
+The presence of an element with the `DT_BIND_NOW` tag and the `DF_BIND_NOW`
+flag<sup id="fnref:4" role="doc-noteref"><a href="#fn:4"
+class="footnote">4</a></sup> in the dynamic section indicates immediate
+binding is enabled for a given binary (see Fig. 10). Conversely, the absence
+of an element with the `DT_BIND_NOW` tag and the `DF_BIND_NOW` flag in the
+dynamic section indicates immediate binding is not enabled for a given
+binary.
+
+The presence of both an element of type `PT_GNU_RELRO` in the program header
+table and of an element with the `DT_BIND_NOW` tag and the `DF_BIND_NOW`
+flag in the dynamic section indicates full RELRO is enabled for a given
+binary (see Fig. 9 and Fig. 10).
+
+<small id="fn:4">4\. And the `DF_1_NOW` flag for some link editors. <a
+href="#fnref:4" class="reversefootnote" role="doc-backlink">↩</a></small>
+
+
+### Heap corruption protection
+
+Heap corruption protection protects memory allocated dynamically by
+performing several checks, such as checks for corrupted links between list
+elements, invalid pointers, invalid sizes, double/multiple “frees” of the
+same memory allocated, and many corner cases of these. These checks are
+implementation specific, and vary per allocator.
+
+[ARM Memory Tagging Extension
+(MTE)](https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/enhancing-memory-safety),
+when available, will provide hardware assistance for a probabilistic
+mitigation to detect memory safety violations by tagging memory allocations,
+and automatically checking that the correct tag is used on every memory
+access.
+
+Rust’s default allocator has historically been
+[jemalloc](http://jemalloc.net/), and it has long been the cause of issues
+and the subject of much discussion[32]–[38]. Consequently, it has been
+removed as the default allocator in favor of the operating system’s standard
+C library default allocator<sup id="fnref:5" role="doc-noteref"><a
+href="#fn:5" class="footnote">5</a></sup> since version 1.32.0
+(2019-01-17)[39].
+
+```ignore
+fn main() {
+    let mut x = Box::new([0; 1024]);
+
+    for i in 0..1026 {
+        unsafe {
+            let elem = x.get_unchecked_mut(i);
+            *elem = 0x4141414141414141u64;
+        }
+    }
+}
+```
+Fig. 11. hello-rust-heap program.
+
+```text
+$ cargo run
+   Compiling hello-rust-heap v0.1.0 (/home/rcvalle/hello-rust-heap)
+    Finished dev [unoptimized + debuginfo] target(s) in 0.25s
+     Running `target/debug/hello-rust-heap`
+free(): invalid next size (normal)
+Aborted
+```
+Fig. 12. Build and execution of hello-rust-heap with debug assertions
+enabled.
+
+```text
+$ cargo run --release
+   Compiling hello-rust-heap v0.1.0 (/home/rcvalle/hello-rust-heap)
+    Finished release [optimized] target(s) in 0.25s
+     Running `target/release/hello-rust-heap`
+free(): invalid next size (normal)
+Aborted
+```
+Fig. 13. Build and execution of hello-rust-heap with debug assertions
+disabled.
+
+Heap corruption checks are being performed when using the default allocator
+(i.e., the GNU Allocator) as seen in Fig. 12 and Fig. 13.
+
+<small id="fn:5">5\. Linux's standard C library default allocator is the GNU
+Allocator, which is derived from ptmalloc (pthreads malloc) by Wolfram
+Gloger, which in turn is derived from dlmalloc (Doug Lea malloc) by Doug
+Lea. <a href="#fnref:5" class="reversefootnote"
+role="doc-backlink">↩</a></small>
+
+
+### Stack smashing protection
+
+Stack smashing protection protects programs from stack-based buffer
+overflows by inserting a random guard value between local variables and the
+saved return instruction pointer, and checking if this value has changed
+when returning from a function. This is also known as “Stack Protector” or
+“Stack Smashing Protector (SSP)”.
+
+The Rust compiler does not support stack smashing protection. However, more
+comprehensive alternatives to stack smashing protection exist, such as
+shadow and safe stack (see backward-edge control flow protection).
+
+![Screenshot of IDA Pro listing cross references to __stack_chk_fail in hello-rust.](images/image3.png "Cross references to __stack_chk_fail in hello-rust.")
+Fig. 14. IDA Pro listing cross references to `__stack_chk_fail` in
+hello-rust.
+
+To check if stack smashing protection is enabled for a given binary, search
+for cross references to `__stack_chk_fail`. The only cross references to
+`__stack_chk_fail` in hello-rust are from the statically-linked libbacktrace
+library (see Fig. 14).
+
+
+### Forward-edge control flow protection
+
+Forward-edge control flow protection protects programs from having its
+control flow changed/hijacked by performing checks to ensure that
+destinations of indirect branches are one of their valid destinations in the
+control flow graph. The comprehensiveness of these checks vary per
+implementation. This is also known as “forward-edge control flow integrity
+(CFI)”.
+
+Newer processors provide hardware assistance for forward-edge control flow
+protection, such as ARM Branch Target Identification (BTI), ARM Pointer
+Authentication, and Intel Indirect Branch Tracking (IBT) as part of Intel
+Control-flow Enforcement Technology (CET). However, ARM BTI and Intel IBT
+-based implementations are less comprehensive than software-based
+implementations such as [LLVM ControlFlowIntegrity
+(CFI)](https://clang.llvm.org/docs/ControlFlowIntegrity.html), and the
+commercially available [grsecurity/PaX Reuse Attack Protector
+(RAP)](https://grsecurity.net/rap_faq).
+
+The Rust compiler does not support forward-edge control flow protection on
+Linux<sup id="fnref:6" role="doc-noteref"><a href="#fn:6"
+class="footnote">6</a></sup>. There is work currently ongoing to add support
+for the [sanitizers](https://github.com/google/sanitizers)[40], which may or
+may not include support for LLVM CFI.
+
+```text
+$ readelf -s target/release/hello-rust | grep __cfi_init
+```
+Fig. 15. Checking if LLVM CFI is enabled for a given binary.
+
+The presence of the `__cfi_init` symbol (and references to `__cfi_check`)
+indicates that LLVM CFI (i.e., forward-edge control flow protection) is
+enabled for a given binary. Conversely, the absence of the `__cfi_init`
+symbol (and references to `__cfi_check`) indicates that LLVM CFI is not
+enabled for a given binary (see Fig. 15).
+
+<small id="fn:6">6\. It supports Control Flow Guard (CFG) on Windows (see
+<https://github.com/rust-lang/rust/issues/68793>). <a href="#fnref:6"
+class="reversefootnote" role="doc-backlink">↩</a></small>
+
+
+### Backward-edge control flow protection
+
+**Shadow stack** protects saved return instruction pointers from being
+overwritten by storing a copy of them on a separate (shadow) stack, and
+using these copies as authoritative values when returning from functions.
+This is also known as “ShadowCallStack” and “Return Flow Guard”, and is
+considered an implementation of backward-edge control flow protection (or
+“backward-edge CFI”).
+
+**Safe stack** protects not only the saved return instruction pointers, but
+also register spills and some local variables from being overwritten by
+storing unsafe variables, such as large arrays, on a separate (unsafe)
+stack, and using these unsafe variables on the separate stack instead. This
+is also known as “SafeStack”, and is also considered an implementation of
+backward-edge control flow protection.
+
+Both shadow and safe stack are intended to be a more comprehensive
+alternatives to stack smashing protection as they protect the saved return
+instruction pointers (and other data in the case of safe stack) from
+arbitrary writes and non-linear out-of-bounds writes.
+
+Newer processors provide hardware assistance for backward-edge control flow
+protection, such as ARM Pointer Authentication, and Intel Shadow Stack as
+part of Intel CET.
+
+The Rust compiler does not support shadow or safe stack. There is work
+currently ongoing to add support for the sanitizers[40], which may or may
+not include support for safe stack<sup id="fnref:7" role="doc-noteref"><a
+href="#fn:7" class="footnote">7</a></sup>.
+
+```text
+$ readelf -s target/release/hello-rust | grep __safestack_init
+```
+Fig. 16. Checking if LLVM SafeStack is enabled for a given binary.
+
+The presence of the `__safestack_init` symbol indicates that LLVM SafeStack
+is enabled for a given binary. Conversely, the absence of the
+`__safestack_init` symbol indicates that LLVM SafeStack is not enabled for a
+given binary (see Fig. 16).
+
+<small id="fn:7">7\. The shadow stack implementation for the AMD64
+architecture and equivalent in LLVM was removed due to performance and
+security issues. <a href="#fnref:7" class="reversefootnote"
+role="doc-backlink">↩</a></small>
+
+
+## Appendix
+
+As of the latest version of the [Linux Standard Base (LSB) Core
+Specification](https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/progheader.html),
+the `PT_GNU_STACK` program header indicates whether the stack should be
+executable, and the absence of this header indicates that the stack should
+be executable. However, the Linux kernel currently sets the
+`READ_IMPLIES_EXEC` personality upon loading any executable with the
+`PT_GNU_STACK` program header and the `PF_X `flag set or with the absence of
+this header, resulting in not only the stack, but also all readable virtual
+memory mappings being executable.
+
+An attempt to fix this [was made in
+2012](https://lore.kernel.org/lkml/f298f914-2239-44e4-8aa1-a51282e7fac0@zmail15.collab.prod.int.phx2.redhat.com/),
+and another [was made in
+2020](https://lore.kernel.org/kernel-hardening/20200327064820.12602-1-keescook@chromium.org/).
+The former never landed, and the latter partially fixed it, but introduced
+other issues—the absence of the `PT_GNU_STACK` program header still causes
+not only the stack, but also all readable virtual memory mappings to be
+executable in some architectures, such as IA-32 and equivalent (or causes
+the stack to be non-executable in some architectures, such as AMD64 and
+equivalent, contradicting the LSB).
+
+The `READ_IMPLIES_EXEC` personality needs to be completely separated from
+the `PT_GNU_STACK` program header by having a separate option for it (or
+setarch -X could just be used whenever `READ_IMPLIES_EXEC` is needed), and
+the absence of the `PT_GNU_STACK` program header needs to have more secure
+defaults (unrelated to `READ_IMPLIES_EXEC`).
+
+
+## References
+
+1. D. Hosfelt. “Fearless security: memory safety.” Mozilla Hacks.
+   <https://hacks.mozilla.org/2019/01/fearless-security-memory-safety/>.
+
+2. D. Hosfelt. “Fearless security: thread safety.” Mozilla Hacks.
+   <https://hacks.mozilla.org/2019/02/fearless-security-thread-safety/>.
+
+3. S. Klabnik and C. Nichols. “What Is Ownership?.” The Rust Programming
+   Language. <https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html>.
+
+4. S. Klabnik and C. Nichols. “References and Borrowing.” The Rust
+   Programming Language.
+   <https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html>.
+
+5. S. Klabnik and C. Nichols. “The Slice Type.” The Rust Programming
+   Language. <https://doc.rust-lang.org/book/ch04-03-slices.html>.
+
+6. S. Klabnik and C. Nichols. “Unsafe Rust.” The Rust Programming Language.
+   <https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html>.
+
+7. S. Davidoff. “How Rust’s standard library was vulnerable for years and
+   nobody noticed.” Medium.
+   <https://medium.com/@shnatsel/how-rusts-standard-library-was-vulnerable-for-years-and-nobody-noticed-aebf0503c3d6>.
+
+8. “Improper restriction of operations within the bounds of a memory buffer
+   (CWE-119).” MITRE CWE List.
+   <https://cwe.mitre.org/data/definitions/119.html>.
+
+9. “Concurrency issues (CWE-557).” MITRE CWE List.
+   <https://cwe.mitre.org/data/definitions/557.html>.
+
+10. K. McAllister. “Memory exploit mitigations #15179.” GitHub.
+    <https://github.com/rust-lang/rust/issues/15179>.
+
+11. K. McAllister. “RFC: Memory exploit mitigation #145.” GitHub.
+    <https://github.com/rust-lang/rfcs/pull/145>.
+
+12. K. McAllister. “RFC: Memory exploit mitigation.” GitHub.
+    <https://github.com/kmcallister/rfcs/blob/hardening/active/0000-memory-exploit-mitigation.md>.
+
+13. D. Micay. “Enable PIE by default on Linux for full ASLR #16340.” GitHub.
+    <https://github.com/rust-lang/rust/pull/16340>.
+
+14. N. Matsakis. “Integer overflow #560.” GitHub.
+    <https://github.com/rust-lang/rfcs/pull/560>.
+
+15. G. Lehel and N. Matsakis. “Integer overflow.” GitHub.
+    <https://rust-lang.github.io/rfcs/0560-integer-overflow.html>.
+
+16. A. Turon. “Tracking issue for integer overflow (RFC 560) #22020.”
+    GitHub. <https://github.com/rust-lang/rust/issues/22020>.
+
+17. H. Wilson. “Myths and legends about integer overflow in Rust.” Huon on
+    the Internet.
+    <http://huonw.github.io/blog/2016/04/myths-and-legends-about-integer-overflow-in-rust/>.
+
+18. B. Anderson. “Stabilize -C overflow-checks #1535.” GitHub.
+    <https://github.com/rust-lang/rfcs/pull/1535>.
+
+19. B. Anderson. “Stable overflow checks.” GitHub.
+    <https://github.com/brson/rfcs/blob/overflow/text/0000-stable-overflow-checks.md>.
+
+20. N. Froyd. “Add -C overflow-checks option #40037.” GitHub.
+    <https://github.com/rust-lang/rust/pull/40037>.
+
+21. R. Á. de Espíndola. “rustc requires executable stack #798.” GitHub.
+    <https://github.com/rust-lang/rust/issues/798>.
+
+22. A. Seipp. “Make sure librustrt.so is linked with a non-executable stack.
+    #1066.” GitHub. <https://github.com/rust-lang/rust/pull/1066>.
+
+23. D. Micay. “Rust binaries should not have an executable stack #5643.”
+    GitHub. <https://github.com/rust-lang/rust/issues/5643>.
+
+24. D. Micay. “Mark the assembly object stacks as non-executable #5647.”
+    GitHub. <https://github.com/rust-lang/rust/pull/5647>.
+
+25. A. Clark. “Explicitly disable stack execution on linux and bsd #30859.”
+    GitHub. <https://github.com/rust-lang/rust/pull/30859>.
+
+26. “Replace stack overflow checking with stack probes #16012.” GitHub.
+    <https://github.com/rust-lang/rust/issues/16012>.
+
+27. B. Striegel. “Extend stack probe support to non-tier-1 platforms, and
+    clarify policy for mitigating LLVM-dependent unsafety #43241.” GitHub.
+    <https://github.com/rust-lang/rust/issues/43241>.
+
+28. A. Crichton. “rustc: Implement stack probes for x86 #42816.” GitHub.
+    <https://github.com/rust-lang/rust/pull/42816>.
+
+29. A. Crichton. “Add \_\_rust\_probestack intrinsic #175.” GitHub.
+    <https://github.com/rust-lang/compiler-builtins/pull/175>.
+
+30. B. Anderson. “Consider applying -Wl,-z,relro or -Wl,-z,relro,-z,now by
+    default #29877.” GitHub. <https://github.com/rust-lang/rust/issues/29877>.
+
+31. J. Löthberg. “Add support for full RELRO #43170.” GitHub.
+    <https://github.com/rust-lang/rust/pull/43170>.
+
+32. N. Matsakis. “Allocators in Rust.” Baby Steps.
+    <http://smallcultfollowing.com/babysteps/blog/2014/11/14/allocators-in-rust/>.
+
+33. A. Crichton. “RFC: Allow changing the default allocator #1183.” GitHub.
+    <https://github.com/rust-lang/rfcs/pull/1183>.
+
+34. A. Crichton. “RFC: Swap out jemalloc.” GitHub.
+    <https://rust-lang.github.io/rfcs/1183-swap-out-jemalloc.html>.
+
+35. A. Crichton. “Tracking issue for changing the global, default allocator
+    (RFC 1974) #27389.” GitHub.
+    <https://github.com/rust-lang/rust/issues/27389>.
+
+36. S. Fackler. “Prepare global allocators for stabilization #1974.” GitHub.
+    <https://github.com/rust-lang/rfcs/pull/1974>.
+
+37. A. Crichton. “RFC: Global allocators.” GitHub.
+    <https://rust-lang.github.io/rfcs/1974-global-allocators.html>.
+
+38. B. Anderson. “Switch the default global allocator to System, remove
+    alloc\_jemalloc, use jemallocator in rustc #36963.” GitHub.
+    <https://github.com/rust-lang/rust/issues/36963>.
+
+39. A. Crichton. “Remove the alloc\_jemalloc crate #55238.” GitHub.
+    <https://github.com/rust-lang/rust/pull/55238>.
+
+40. J. Aparicio. 2017. “Tracking issue for sanitizer support #39699.”
+    <https://github.com/rust-lang/rust/issues/39699>.
diff --git a/src/doc/rustc/src/images/image1.png b/src/doc/rustc/src/images/image1.png
new file mode 100644
index 00000000000..ee2d3fd4f43
--- /dev/null
+++ b/src/doc/rustc/src/images/image1.png
Binary files differdiff --git a/src/doc/rustc/src/images/image2.png b/src/doc/rustc/src/images/image2.png
new file mode 100644
index 00000000000..03061e1f0b1
--- /dev/null
+++ b/src/doc/rustc/src/images/image2.png
Binary files differdiff --git a/src/doc/rustc/src/images/image3.png b/src/doc/rustc/src/images/image3.png
new file mode 100644
index 00000000000..a49e14b5ed2
--- /dev/null
+++ b/src/doc/rustc/src/images/image3.png
Binary files differdiff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py
index b5ade324bba..b74d47a8002 100644
--- a/src/etc/gdb_providers.py
+++ b/src/etc/gdb_providers.py
@@ -216,6 +216,10 @@ def children_of_btree_map(map):
             internal_type = lookup_type(internal_type_name)
             return node.cast(internal_type.pointer())
 
+        if node_ptr.type.name.startswith("alloc::collections::btree::node::BoxedNode<"):
+            # BACKCOMPAT: rust 1.49
+            node_ptr = node_ptr["ptr"]
+        node_ptr = unwrap_unique_or_non_null(node_ptr)
         leaf = node_ptr.dereference()
         keys = leaf["keys"]
         vals = leaf["vals"]
@@ -224,9 +228,8 @@ def children_of_btree_map(map):
 
         for i in xrange(0, length + 1):
             if height > 0:
-                boxed_child_node = edges[i]["value"]["value"]
-                child_node = unwrap_unique_or_non_null(boxed_child_node["ptr"])
-                for child in children_of_node(child_node, height - 1):
+                child_ptr = edges[i]["value"]["value"]
+                for child in children_of_node(child_ptr, height - 1):
                     yield child
             if i < length:
                 # Avoid "Cannot perform pointer math on incomplete type" on zero-sized arrays.
@@ -239,9 +242,6 @@ def children_of_btree_map(map):
         if root.type.name.startswith("core::option::Option<"):
             root = root.cast(gdb.lookup_type(root.type.name[21:-1]))
         node_ptr = root["node"]
-        if node_ptr.type.name.startswith("alloc::collections::btree::node::BoxedNode<"):
-            node_ptr = node_ptr["ptr"]
-        node_ptr = unwrap_unique_or_non_null(node_ptr)
         height = root["height"]
         for child in children_of_node(node_ptr, height):
             yield child
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index d58a88957df..e76ca1022a9 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -234,9 +234,8 @@ impl Clean<Item> for doctree::Module<'_> {
         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.items.iter().map(|x| x.clean(cx)));
+        items.extend(self.items.iter().map(|x| x.clean(cx)).flatten());
         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)));
 
@@ -1922,8 +1921,8 @@ impl Clean<BareFunctionDecl> for hir::BareFnTy<'_> {
     }
 }
 
-impl Clean<Item> for (&hir::Item<'_>, Option<Ident>) {
-    fn clean(&self, cx: &DocContext<'_>) -> Item {
+impl Clean<Vec<Item>> for (&hir::Item<'_>, Option<Ident>) {
+    fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
         use hir::ItemKind;
 
         let (item, renamed) = self;
@@ -1977,10 +1976,11 @@ impl Clean<Item> for (&hir::Item<'_>, Option<Ident>) {
                 fields: variant_data.fields().clean(cx),
                 fields_stripped: false,
             }),
+            ItemKind::Impl { .. } => return clean_impl(item, cx),
             _ => unreachable!("not yet converted"),
         };
 
-        Item::from_def_id_and_parts(def_id, Some(name), kind, cx)
+        vec![Item::from_def_id_and_parts(def_id, Some(name), kind, cx)]
     }
 }
 
@@ -2005,57 +2005,53 @@ impl Clean<ImplPolarity> for ty::ImplPolarity {
     }
 }
 
-impl Clean<Vec<Item>> for doctree::Impl<'_> {
-    fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
-        let mut ret = Vec::new();
-        let trait_ = self.trait_.clean(cx);
-        let items = self.items.iter().map(|ii| ii.clean(cx)).collect::<Vec<_>>();
-        let def_id = cx.tcx.hir().local_def_id(self.id);
-
-        // If this impl block is an implementation of the Deref trait, then we
-        // need to try inlining the target's inherent impl blocks as well.
-        if trait_.def_id() == cx.tcx.lang_items().deref_trait() {
-            build_deref_target_impls(cx, &items, &mut ret);
+fn clean_impl(impl_: &hir::Item<'_>, cx: &DocContext<'_>) -> Vec<Item> {
+    let mut ret = Vec::new();
+    let (trait_, items, for_, unsafety, generics) = match &impl_.kind {
+        hir::ItemKind::Impl { of_trait, items, self_ty, unsafety, generics, .. } => {
+            (of_trait, items, self_ty, *unsafety, generics)
         }
-
-        let provided: FxHashSet<String> = trait_
-            .def_id()
-            .map(|did| {
-                cx.tcx.provided_trait_methods(did).map(|meth| meth.ident.to_string()).collect()
-            })
-            .unwrap_or_default();
-
-        let for_ = self.for_.clean(cx);
-        let type_alias = for_.def_id().and_then(|did| match cx.tcx.def_kind(did) {
-            DefKind::TyAlias => Some(cx.tcx.type_of(did).clean(cx)),
-            _ => None,
+        _ => unreachable!(),
+    };
+    let trait_ = trait_.clean(cx);
+    let items = items.iter().map(|ii| cx.tcx.hir().impl_item(ii.id).clean(cx)).collect::<Vec<_>>();
+    let def_id = cx.tcx.hir().local_def_id(impl_.hir_id);
+
+    // If this impl block is an implementation of the Deref trait, then we
+    // need to try inlining the target's inherent impl blocks as well.
+    if trait_.def_id() == cx.tcx.lang_items().deref_trait() {
+        build_deref_target_impls(cx, &items, &mut ret);
+    }
+
+    let provided: FxHashSet<String> = trait_
+        .def_id()
+        .map(|did| cx.tcx.provided_trait_methods(did).map(|meth| meth.ident.to_string()).collect())
+        .unwrap_or_default();
+
+    let for_ = for_.clean(cx);
+    let type_alias = for_.def_id().and_then(|did| match cx.tcx.def_kind(did) {
+        DefKind::TyAlias => Some(cx.tcx.type_of(did).clean(cx)),
+        _ => None,
+    });
+    let make_item = |trait_: Option<Type>, for_: Type, items: Vec<Item>| {
+        let kind = ImplItem(Impl {
+            unsafety,
+            generics: generics.clean(cx),
+            provided_trait_methods: provided.clone(),
+            trait_,
+            for_,
+            items,
+            polarity: Some(cx.tcx.impl_polarity(def_id).clean(cx)),
+            synthetic: false,
+            blanket_impl: None,
         });
-        let make_item = |trait_: Option<Type>, for_: Type, items: Vec<Item>| Item {
-            name: None,
-            attrs: self.attrs.clean(cx),
-            source: self.span.clean(cx),
-            def_id: def_id.to_def_id(),
-            visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id),
-            deprecation: cx.deprecation(self.id).clean(cx),
-            kind: ImplItem(Impl {
-                unsafety: self.unsafety,
-                generics: self.generics.clean(cx),
-                provided_trait_methods: provided.clone(),
-                trait_,
-                for_,
-                items,
-                polarity: Some(cx.tcx.impl_polarity(def_id).clean(cx)),
-                synthetic: false,
-                blanket_impl: None,
-            }),
-        };
-        if let Some(type_alias) = type_alias {
-            ret.push(make_item(trait_.clone(), type_alias, items.clone()));
-        }
-        ret.push(make_item(trait_, for_, items));
-        ret
+        Item::from_hir_id_and_parts(impl_.hir_id, None, kind, cx)
+    };
+    if let Some(type_alias) = type_alias {
+        ret.push(make_item(trait_.clone(), type_alias, items.clone()));
     }
+    ret.push(make_item(trait_, for_, items));
+    ret
 }
 
 impl Clean<Vec<Item>> for doctree::ExternCrate<'_> {
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 413f5bdf521..b7cc0f19459 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -1,4 +1,3 @@
-use rustc_attr as attr;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::{self, Lrc};
 use rustc_driver::abort_on_err;
@@ -156,21 +155,6 @@ impl<'tcx> DocContext<'tcx> {
             def_id.as_local().map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id))
         }
     }
-
-    crate fn stability(&self, id: HirId) -> Option<attr::Stability> {
-        self.tcx
-            .hir()
-            .opt_local_def_id(id)
-            .and_then(|def_id| self.tcx.lookup_stability(def_id.to_def_id()))
-            .cloned()
-    }
-
-    crate fn deprecation(&self, id: HirId) -> Option<attr::Deprecation> {
-        self.tcx
-            .hir()
-            .opt_local_def_id(id)
-            .and_then(|def_id| self.tcx.lookup_deprecation(def_id.to_def_id()))
-    }
 }
 
 /// Creates a new diagnostic `Handler` that can be used to emit warnings and errors.
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index d56328cc2aa..4d2fe04123b 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -23,7 +23,6 @@ crate struct Module<'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>,
@@ -44,7 +43,6 @@ impl Module<'hir> {
             mods: Vec::new(),
             items: Vec::new(),
             traits: Vec::new(),
-            impls: Vec::new(),
             foreigns: Vec::new(),
             macros: Vec::new(),
             proc_macros: Vec::new(),
@@ -89,22 +87,6 @@ crate struct Trait<'hir> {
     crate id: hir::HirId,
 }
 
-#[derive(Debug)]
-crate struct Impl<'hir> {
-    crate unsafety: hir::Unsafety,
-    crate polarity: hir::ImplPolarity,
-    crate defaultness: hir::Defaultness,
-    crate constness: hir::Constness,
-    crate generics: &'hir hir::Generics<'hir>,
-    crate trait_: &'hir Option<hir::TraitRef<'hir>>,
-    crate for_: &'hir hir::Ty<'hir>,
-    crate items: Vec<&'hir hir::ImplItem<'hir>>,
-    crate attrs: &'hir [ast::Attribute],
-    crate span: Span,
-    crate vis: &'hir hir::Visibility<'hir>,
-    crate id: hir::HirId,
-}
-
 crate struct ForeignItem<'hir> {
     crate id: hir::HirId,
     crate name: Symbol,
diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs
index a72860ef0a8..285fabdc372 100644
--- a/src/librustdoc/fold.rs
+++ b/src/librustdoc/fold.rs
@@ -16,7 +16,7 @@ impl StripItem {
 
 crate trait DocFolder: Sized {
     fn fold_item(&mut self, item: Item) -> Option<Item> {
-        self.fold_item_recur(item)
+        Some(self.fold_item_recur(item))
     }
 
     /// don't override!
@@ -71,15 +71,12 @@ crate trait DocFolder: Sized {
     }
 
     /// don't override!
-    fn fold_item_recur(&mut self, item: Item) -> Option<Item> {
-        let Item { attrs, name, source, visibility, def_id, kind, stability, deprecation } = item;
-
-        let kind = match kind {
+    fn fold_item_recur(&mut self, mut item: Item) -> Item {
+        item.kind = match item.kind {
             StrippedItem(box i) => StrippedItem(box self.fold_inner_recur(i)),
-            _ => self.fold_inner_recur(kind),
+            _ => self.fold_inner_recur(item.kind),
         };
-
-        Some(Item { attrs, name, source, kind, visibility, stability, deprecation, def_id })
+        item
     }
 
     fn fold_mod(&mut self, m: Module) -> Module {
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 917c1a95fdb..39b750279ac 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -421,55 +421,52 @@ impl DocFolder for Cache {
 
         // Once we've recursively found all the generics, hoard off all the
         // implementations elsewhere.
-        let ret = self.fold_item_recur(item).and_then(|item| {
-            if let clean::Item { kind: clean::ImplItem(_), .. } = item {
-                // Figure out the id of this impl. This may map to a
-                // primitive rather than always to a struct/enum.
-                // Note: matching twice to restrict the lifetime of the `i` borrow.
-                let mut dids = FxHashSet::default();
-                if let clean::Item { kind: clean::ImplItem(ref i), .. } = item {
-                    match i.for_ {
-                        clean::ResolvedPath { did, .. }
-                        | clean::BorrowedRef {
-                            type_: box clean::ResolvedPath { did, .. }, ..
-                        } => {
-                            dids.insert(did);
-                        }
-                        ref t => {
-                            let did = t
-                                .primitive_type()
-                                .and_then(|t| self.primitive_locations.get(&t).cloned());
+        let item = self.fold_item_recur(item);
+        let ret = if let clean::Item { kind: clean::ImplItem(_), .. } = item {
+            // Figure out the id of this impl. This may map to a
+            // primitive rather than always to a struct/enum.
+            // Note: matching twice to restrict the lifetime of the `i` borrow.
+            let mut dids = FxHashSet::default();
+            if let clean::Item { kind: clean::ImplItem(ref i), .. } = item {
+                match i.for_ {
+                    clean::ResolvedPath { did, .. }
+                    | clean::BorrowedRef { type_: box clean::ResolvedPath { did, .. }, .. } => {
+                        dids.insert(did);
+                    }
+                    ref t => {
+                        let did = t
+                            .primitive_type()
+                            .and_then(|t| self.primitive_locations.get(&t).cloned());
 
-                            if let Some(did) = did {
-                                dids.insert(did);
-                            }
+                        if let Some(did) = did {
+                            dids.insert(did);
                         }
                     }
+                }
 
-                    if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
-                        for bound in generics {
-                            if let Some(did) = bound.def_id() {
-                                dids.insert(did);
-                            }
+                if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
+                    for bound in generics {
+                        if let Some(did) = bound.def_id() {
+                            dids.insert(did);
                         }
                     }
-                } else {
-                    unreachable!()
-                };
-                let impl_item = Impl { impl_item: item };
-                if impl_item.trait_did().map_or(true, |d| self.traits.contains_key(&d)) {
-                    for did in dids {
-                        self.impls.entry(did).or_insert(vec![]).push(impl_item.clone());
-                    }
-                } else {
-                    let trait_did = impl_item.trait_did().expect("no trait did");
-                    self.orphan_trait_impls.push((trait_did, dids, impl_item));
                 }
-                None
             } else {
-                Some(item)
+                unreachable!()
+            };
+            let impl_item = Impl { impl_item: item };
+            if impl_item.trait_did().map_or(true, |d| self.traits.contains_key(&d)) {
+                for did in dids {
+                    self.impls.entry(did).or_insert(vec![]).push(impl_item.clone());
+                }
+            } else {
+                let trait_did = impl_item.trait_did().expect("no trait did");
+                self.orphan_trait_impls.push((trait_did, dids, impl_item));
             }
-        });
+            None
+        } else {
+            Some(item)
+        };
 
         if pushed {
             self.stack.pop().expect("stack already empty");
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 0f82649409f..e7b5a90d84d 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -60,7 +60,7 @@ impl<'a> DocFolder for SourceCollector<'a> {
                 }
             };
         }
-        self.fold_item_recur(item)
+        Some(self.fold_item_recur(item))
     }
 }
 
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index aca218e5381..3f9978c8fca 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -268,6 +268,6 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> {
             }
         }
 
-        self.fold_item_recur(i)
+        Some(self.fold_item_recur(i))
     }
 }
diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs
index a48fa738e3b..0c76dc571be 100644
--- a/src/librustdoc/passes/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/check_code_block_syntax.rs
@@ -105,7 +105,7 @@ impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> {
             }
         }
 
-        self.fold_item_recur(item)
+        Some(self.fold_item_recur(item))
     }
 }
 
diff --git a/src/librustdoc/passes/collapse_docs.rs b/src/librustdoc/passes/collapse_docs.rs
index 1f9f5c58e5a..e1ba75baa0f 100644
--- a/src/librustdoc/passes/collapse_docs.rs
+++ b/src/librustdoc/passes/collapse_docs.rs
@@ -23,7 +23,7 @@ struct Collapser;
 impl fold::DocFolder for Collapser {
     fn fold_item(&mut self, mut i: Item) -> Option<Item> {
         i.attrs.collapse_doc_comments();
-        self.fold_item_recur(i)
+        Some(self.fold_item_recur(i))
     }
 }
 
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index fd09ba04b3d..6aa46b24a0e 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -858,7 +858,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
             // we don't display docs on `extern crate` items anyway, so don't process them.
             clean::ExternCrateItem(..) => {
                 debug!("ignoring extern crate item {:?}", item.def_id);
-                return self.fold_item_recur(item);
+                return Some(self.fold_item_recur(item));
             }
             clean::ImportItem(Import { kind: clean::ImportKind::Simple(ref name, ..), .. }) => {
                 Some(name.clone())
@@ -958,7 +958,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
             }
         }
 
-        if item.is_mod() {
+        Some(if item.is_mod() {
             if !item.attrs.inner_docs {
                 self.mod_ids.push(item.def_id);
             }
@@ -968,7 +968,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
             ret
         } else {
             self.fold_item_recur(item)
-        }
+        })
     }
 }
 
@@ -1022,7 +1022,7 @@ impl LinkCollector<'_, '_> {
             (link.trim(), None)
         };
 
-        if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, ".contains(ch))) {
+        if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, !".contains(ch))) {
             return None;
         }
 
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index 2946db1f462..4c3defabc32 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -133,7 +133,7 @@ impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> {
             }
         }
 
-        self.fold_item_recur(i)
+        Some(self.fold_item_recur(i))
     }
 }
 
@@ -152,7 +152,7 @@ impl DocFolder for ItemCollector {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
         self.items.insert(i.def_id);
 
-        self.fold_item_recur(i)
+        Some(self.fold_item_recur(i))
     }
 }
 
diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs
index 60fe8080f56..299a73c8a01 100644
--- a/src/librustdoc/passes/doc_test_lints.rs
+++ b/src/librustdoc/passes/doc_test_lints.rs
@@ -41,7 +41,7 @@ impl<'a, 'tcx> DocFolder for PrivateItemDocTestLinter<'a, 'tcx> {
 
         look_for_tests(&cx, &dox, &item);
 
-        self.fold_item_recur(item)
+        Some(self.fold_item_recur(item))
     }
 }
 
diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs
index 70748633117..a7a1ba1118d 100644
--- a/src/librustdoc/passes/html_tags.rs
+++ b/src/librustdoc/passes/html_tags.rs
@@ -178,7 +178,7 @@ impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> {
             Some(hir_id) => hir_id,
             None => {
                 // If non-local, no need to check anything.
-                return self.fold_item_recur(item);
+                return Some(self.fold_item_recur(item));
             }
         };
         let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
@@ -223,6 +223,6 @@ impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> {
             }
         }
 
-        self.fold_item_recur(item)
+        Some(self.fold_item_recur(item))
     }
 }
diff --git a/src/librustdoc/passes/non_autolinks.rs b/src/librustdoc/passes/non_autolinks.rs
index c9c49968b93..1f411b997f8 100644
--- a/src/librustdoc/passes/non_autolinks.rs
+++ b/src/librustdoc/passes/non_autolinks.rs
@@ -68,7 +68,7 @@ impl<'a, 'tcx> DocFolder for NonAutolinksLinter<'a, 'tcx> {
             Some(hir_id) => hir_id,
             None => {
                 // If non-local, no need to check anything.
-                return self.fold_item_recur(item);
+                return Some(self.fold_item_recur(item));
             }
         };
         let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
@@ -133,6 +133,6 @@ impl<'a, 'tcx> DocFolder for NonAutolinksLinter<'a, 'tcx> {
             }
         }
 
-        self.fold_item_recur(item)
+        Some(self.fold_item_recur(item))
     }
 }
diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs
index fbfc693c534..6722d7c2fc9 100644
--- a/src/librustdoc/passes/propagate_doc_cfg.rs
+++ b/src/librustdoc/passes/propagate_doc_cfg.rs
@@ -39,6 +39,6 @@ impl DocFolder for CfgPropagator {
         let result = self.fold_item_recur(item);
         self.parent_cfg = old_parent_cfg;
 
-        result
+        Some(result)
     }
 }
diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs
index 6da753ea6e6..6b59eb8cf28 100644
--- a/src/librustdoc/passes/strip_hidden.rs
+++ b/src/librustdoc/passes/strip_hidden.rs
@@ -47,7 +47,7 @@ impl<'a> DocFolder for Stripper<'a> {
                     // strip things like impl methods but when doing so
                     // we must not add any items to the `retained` set.
                     let old = mem::replace(&mut self.update_retained, false);
-                    let ret = StripItem(self.fold_item_recur(i).unwrap()).strip();
+                    let ret = StripItem(self.fold_item_recur(i)).strip();
                     self.update_retained = old;
                     return ret;
                 }
@@ -58,6 +58,6 @@ impl<'a> DocFolder for Stripper<'a> {
                 self.retained.insert(i.def_id);
             }
         }
-        self.fold_item_recur(i)
+        Some(self.fold_item_recur(i))
     }
 }
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
index eb5a61a9d20..444fd593ec9 100644
--- a/src/librustdoc/passes/stripper.rs
+++ b/src/librustdoc/passes/stripper.rs
@@ -22,7 +22,7 @@ impl<'a> DocFolder for Stripper<'a> {
                 let old = mem::replace(&mut self.update_retained, false);
                 let ret = self.fold_item_recur(i);
                 self.update_retained = old;
-                return ret;
+                return Some(ret);
             }
             // These items can all get re-exported
             clean::OpaqueTyItem(..)
@@ -59,7 +59,7 @@ impl<'a> DocFolder for Stripper<'a> {
                 if i.def_id.is_local() && !i.visibility.is_public() {
                     debug!("Stripper: stripping module {:?}", i.name);
                     let old = mem::replace(&mut self.update_retained, false);
-                    let ret = StripItem(self.fold_item_recur(i).unwrap()).strip();
+                    let ret = StripItem(self.fold_item_recur(i)).strip();
                     self.update_retained = old;
                     return ret;
                 }
@@ -107,12 +107,10 @@ impl<'a> DocFolder for Stripper<'a> {
             self.fold_item_recur(i)
         };
 
-        if let Some(ref i) = i {
-            if self.update_retained {
-                self.retained.insert(i.def_id);
-            }
+        if self.update_retained {
+            self.retained.insert(i.def_id);
         }
-        i
+        Some(i)
     }
 }
 
@@ -153,7 +151,7 @@ impl<'a> DocFolder for ImplStripper<'a> {
                 }
             }
         }
-        self.fold_item_recur(i)
+        Some(self.fold_item_recur(i))
     }
 }
 
@@ -164,7 +162,7 @@ impl DocFolder for ImportStripper {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
         match i.kind {
             clean::ExternCrateItem(..) | clean::ImportItem(..) if !i.visibility.is_public() => None,
-            _ => self.fold_item_recur(i),
+            _ => Some(self.fold_item_recur(i)),
         }
     }
 }
diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs
index eb2f066bbde..d0345d1e48c 100644
--- a/src/librustdoc/passes/unindent_comments.rs
+++ b/src/librustdoc/passes/unindent_comments.rs
@@ -23,7 +23,7 @@ struct CommentCleaner;
 impl fold::DocFolder for CommentCleaner {
     fn fold_item(&mut self, mut i: Item) -> Option<Item> {
         i.attrs.unindent_doc_comments();
-        self.fold_item_recur(i)
+        Some(self.fold_item_recur(i))
     }
 }
 
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index c55e5f7690c..37050a57ca0 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -401,37 +401,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 };
                 om.traits.push(t);
             }
-            hir::ItemKind::Impl {
-                unsafety,
-                polarity,
-                defaultness,
-                constness,
-                defaultness_span: _,
-                ref generics,
-                ref of_trait,
-                self_ty,
-                ref items,
-            } => {
+            hir::ItemKind::Impl { ref of_trait, .. } => {
                 // Don't duplicate impls when inlining or if it's implementing a trait, we'll pick
                 // them up regardless of where they're located.
                 if !self.inlining && of_trait.is_none() {
-                    let items =
-                        items.iter().map(|item| self.cx.tcx.hir().impl_item(item.id)).collect();
-                    let i = Impl {
-                        unsafety,
-                        polarity,
-                        defaultness,
-                        constness,
-                        generics,
-                        trait_: of_trait,
-                        for_: self_ty,
-                        items,
-                        attrs: &item.attrs,
-                        id: item.hir_id,
-                        span: item.span,
-                        vis: &item.vis,
-                    };
-                    om.impls.push(i);
+                    om.items.push((item, None));
                 }
             }
         }
diff --git a/src/test/codegen/fewer-names.rs b/src/test/codegen/fewer-names.rs
new file mode 100644
index 00000000000..53a926d49ef
--- /dev/null
+++ b/src/test/codegen/fewer-names.rs
@@ -0,0 +1,20 @@
+// no-system-llvm
+// compile-flags: -Coverflow-checks=no -O
+// revisions: YES NO
+// [YES]compile-flags: -Zfewer-names=yes
+// [NO] compile-flags: -Zfewer-names=no
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn sum(x: u32, y: u32) -> u32 {
+// YES-LABEL: define i32 @sum(i32 %0, i32 %1)
+// YES-NEXT:    %3 = add i32 %1, %0
+// YES-NEXT:    ret i32 %3
+
+// NO-LABEL: define i32 @sum(i32 %x, i32 %y)
+// NO-NEXT:  start:
+// NO-NEXT:    %z = add i32 %y, %x
+// NO-NEXT:    ret i32 %z
+    let z = x + y;
+    z
+}
diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr
index 31e7fc48afd..be98cac94ec 100644
--- a/src/test/rustdoc-ui/intra-link-errors.stderr
+++ b/src/test/rustdoc-ui/intra-link-errors.stderr
@@ -106,6 +106,15 @@ LL | /// [S!]
    |      this link resolves to the struct `S`, which is not in the macro namespace
    |      help: to link to the struct, prefix with `struct@`: `struct@S`
 
+error: unresolved link to `S::h`
+  --> $DIR/intra-link-errors.rs:78:6
+   |
+LL | /// [type@S::h]
+   |      ^^^^^^^^^
+   |      |
+   |      this link resolves to the associated function `h`, which is not in the type namespace
+   |      help: to link to the associated function, add parentheses: `S::h()`
+
 error: unresolved link to `T::g`
   --> $DIR/intra-link-errors.rs:86:6
    |
@@ -121,15 +130,6 @@ error: unresolved link to `T::h`
 LL | /// [T::h!]
    |      ^^^^^ the trait `T` has no macro named `h`
 
-error: unresolved link to `S::h`
-  --> $DIR/intra-link-errors.rs:78:6
-   |
-LL | /// [type@S::h]
-   |      ^^^^^^^^^
-   |      |
-   |      this link resolves to the associated function `h`, which is not in the type namespace
-   |      help: to link to the associated function, add parentheses: `S::h()`
-
 error: unresolved link to `m`
   --> $DIR/intra-link-errors.rs:98:6
    |
diff --git a/src/test/rustdoc/intra-doc-link-generic-params.rs b/src/test/rustdoc/intra-doc-link-generic-params.rs
index 7d7289437ff..1de6410f10c 100644
--- a/src/test/rustdoc/intra-doc-link-generic-params.rs
+++ b/src/test/rustdoc/intra-doc-link-generic-params.rs
@@ -15,8 +15,11 @@
 // @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html"]' 'with the generic, Option<T>'
 
 //! We should also try linking to [`Result<T, E>`]; it has *two* generics!
+//! And [`Result<T, !>`] and [`Result<!, E>`].
 //!
 // @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<T, E>'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<T, !>'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<!, E>'
 
 //! Now let's test a trickier case: [`Vec::<T>::new`], or you could write it
 //! [with parentheses as `Vec::<T>::new()`][Vec::<T>::new()].
diff --git a/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr b/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr
index cfaacf7a5be..73c9ea59c95 100644
--- a/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr
+++ b/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr
@@ -5,6 +5,7 @@ LL | struct ArithArrayLen<const N: usize>([u32; 0 + N]);
    |                                                ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/array-size-in-generic-struct-param.rs:20:15
@@ -13,6 +14,7 @@ LL |     arr: [u8; CFG.arr_size],
    |               ^^^ cannot perform const operation using `CFG`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `CFG`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: `Config` is forbidden as the type of a const generic parameter
   --> $DIR/array-size-in-generic-struct-param.rs:18:21
@@ -21,7 +23,7 @@ LL | struct B<const CFG: Config> {
    |                     ^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/const-generics/const-arg-in-const-arg.min.stderr b/src/test/ui/const-generics/const-arg-in-const-arg.min.stderr
index 7dfe250b78e..042fa9ad958 100644
--- a/src/test/ui/const-generics/const-arg-in-const-arg.min.stderr
+++ b/src/test/ui/const-generics/const-arg-in-const-arg.min.stderr
@@ -5,6 +5,7 @@ LL |     let _: [u8; foo::<T>()];
    |                       ^ cannot perform const operation using `T`
    |
    = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/const-arg-in-const-arg.rs:15:23
@@ -13,6 +14,7 @@ LL |     let _: [u8; bar::<N>()];
    |                       ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/const-arg-in-const-arg.rs:25:23
@@ -21,6 +23,7 @@ LL |     let _ = [0; bar::<N>()];
    |                       ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/const-arg-in-const-arg.rs:30:24
@@ -29,6 +32,7 @@ LL |     let _: Foo<{ foo::<T>() }>;
    |                        ^ cannot perform const operation using `T`
    |
    = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/const-arg-in-const-arg.rs:31:24
@@ -37,6 +41,7 @@ LL |     let _: Foo<{ bar::<N>() }>;
    |                        ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/const-arg-in-const-arg.rs:36:27
@@ -45,6 +50,7 @@ LL |     let _ = Foo::<{ foo::<T>() }>;
    |                           ^ cannot perform const operation using `T`
    |
    = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/const-arg-in-const-arg.rs:37:27
@@ -53,6 +59,7 @@ LL |     let _ = Foo::<{ bar::<N>() }>;
    |                           ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error[E0658]: a non-static lifetime is not allowed in a `const`
   --> $DIR/const-arg-in-const-arg.rs:16:23
diff --git a/src/test/ui/const-generics/const-argument-if-length.min.stderr b/src/test/ui/const-generics/const-argument-if-length.min.stderr
index bce701ade86..8a1074392a5 100644
--- a/src/test/ui/const-generics/const-argument-if-length.min.stderr
+++ b/src/test/ui/const-generics/const-argument-if-length.min.stderr
@@ -5,6 +5,7 @@ LL |     pad: [u8; is_zst::<T>()],
    |                        ^ cannot perform const operation using `T`
    |
    = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> $DIR/const-argument-if-length.rs:17:12
diff --git a/src/test/ui/const-generics/const-param-before-other-params.min.stderr b/src/test/ui/const-generics/const-param-before-other-params.min.stderr
index c7e6d1be421..354c6d0615f 100644
--- a/src/test/ui/const-generics/const-param-before-other-params.min.stderr
+++ b/src/test/ui/const-generics/const-param-before-other-params.min.stderr
@@ -17,7 +17,7 @@ LL | fn bar<const X: (), 'a>(_: &'a ()) {
    |                 ^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `()` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-before-other-params.rs:11:17
@@ -26,7 +26,7 @@ LL | fn foo<const X: (), T>(_: &T) {}
    |                 ^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/const-generics/const-param-elided-lifetime.min.stderr b/src/test/ui/const-generics/const-param-elided-lifetime.min.stderr
index 81dbaee0ec5..ed30182690a 100644
--- a/src/test/ui/const-generics/const-param-elided-lifetime.min.stderr
+++ b/src/test/ui/const-generics/const-param-elided-lifetime.min.stderr
@@ -35,7 +35,7 @@ LL | struct A<const N: &u8>;
    |                   ^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `&'static u8` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-elided-lifetime.rs:16:15
@@ -44,7 +44,7 @@ LL | impl<const N: &u8> A<N> {
    |               ^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `&'static u8` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-elided-lifetime.rs:24:15
@@ -53,7 +53,7 @@ LL | impl<const N: &u8> B for A<N> {}
    |               ^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `&'static u8` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-elided-lifetime.rs:28:17
@@ -62,7 +62,7 @@ LL | fn bar<const N: &u8>() {}
    |                 ^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `&'static u8` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-elided-lifetime.rs:19:21
@@ -71,7 +71,7 @@ LL |     fn foo<const M: &u8>(&self) {}
    |                     ^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to 10 previous errors
 
diff --git a/src/test/ui/const-generics/const-param-type-depends-on-const-param.min.stderr b/src/test/ui/const-generics/const-param-type-depends-on-const-param.min.stderr
index b00a1607876..6b7a218ada5 100644
--- a/src/test/ui/const-generics/const-param-type-depends-on-const-param.min.stderr
+++ b/src/test/ui/const-generics/const-param-type-depends-on-const-param.min.stderr
@@ -17,7 +17,7 @@ LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
    |                                               ^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `[u8; _]` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-type-depends-on-const-param.rs:16:35
@@ -26,7 +26,7 @@ LL | pub struct SelfDependent<const N: [u8; N]>;
    |                                   ^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr
index 359c2d2a22f..573bc66b7c7 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr
+++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr
@@ -5,6 +5,7 @@ LL | type Arr<const N: usize> = [u8; N - 1];
    |                                 ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr
index 46485262cc4..d476a7eb645 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr
+++ b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr
@@ -5,6 +5,7 @@ LL | fn test<const N: usize>() -> [u8; N - 1] where [u8; N - 1]: Default {
    |                                                     ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/simple.rs:8:35
@@ -13,6 +14,7 @@ LL | fn test<const N: usize>() -> [u8; N - 1] where [u8; N - 1]: Default {
    |                                   ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr
index 981d993f589..bd81e0bc5a8 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr
+++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr
@@ -5,6 +5,7 @@ LL | type Arr<const N: usize> = [u8; N - 1];
    |                                 ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/different_byref.min.stderr b/src/test/ui/const-generics/different_byref.min.stderr
index 050b28abe50..e5b393ffe99 100644
--- a/src/test/ui/const-generics/different_byref.min.stderr
+++ b/src/test/ui/const-generics/different_byref.min.stderr
@@ -5,7 +5,7 @@ LL | struct Const<const V: [usize; 1]> {}
    |                       ^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/forbid-non-structural_match-types.min.stderr b/src/test/ui/const-generics/forbid-non-structural_match-types.min.stderr
index 40d8f44cafc..014200178b9 100644
--- a/src/test/ui/const-generics/forbid-non-structural_match-types.min.stderr
+++ b/src/test/ui/const-generics/forbid-non-structural_match-types.min.stderr
@@ -5,7 +5,7 @@ LL | struct B<const X: A>; // ok
    |                   ^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `C` is forbidden as the type of a const generic parameter
   --> $DIR/forbid-non-structural_match-types.rs:15:19
@@ -14,7 +14,7 @@ LL | struct D<const X: C>;
    |                   ^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error[E0741]: `C` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
   --> $DIR/forbid-non-structural_match-types.rs:15:19
diff --git a/src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr b/src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr
index 84449018e46..526f98fe8cd 100644
--- a/src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr
+++ b/src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr
@@ -5,6 +5,7 @@ LL | fn bar<const N: usize>() -> [u32; foo(N)] {
    |                                       ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/generic-function-call-in-array-length.rs:12:13
@@ -13,6 +14,7 @@ LL |     [0; foo(N)]
    |             ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/generic-sum-in-array-length.min.stderr b/src/test/ui/const-generics/generic-sum-in-array-length.min.stderr
index d3f7143327e..e531b612b56 100644
--- a/src/test/ui/const-generics/generic-sum-in-array-length.min.stderr
+++ b/src/test/ui/const-generics/generic-sum-in-array-length.min.stderr
@@ -5,6 +5,7 @@ LL | fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {}
    |                                                     ^ cannot perform const operation using `A`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `A`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/generic-sum-in-array-length.rs:7:57
@@ -13,6 +14,7 @@ LL | fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {}
    |                                                         ^ cannot perform const operation using `B`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `B`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr b/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr
index 20a8d9fdaab..02467df193c 100644
--- a/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr
+++ b/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr
@@ -5,6 +5,7 @@ LL |     T: Trait<{std::intrinsics::type_name::<T>()}>
    |                                            ^ cannot perform const operation using `T`
    |
    = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: `&'static str` is forbidden as the type of a const generic parameter
   --> $DIR/intrinsics-type_name-as-const-argument.rs:10:22
@@ -13,7 +14,7 @@ LL | trait Trait<const S: &'static str> {}
    |                      ^^^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr b/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr
index 526807f0a24..2eaef95c232 100644
--- a/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr
+++ b/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr
@@ -5,6 +5,7 @@ LL | pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
    |                                             ^^^^^ cannot perform const operation using `COUNT`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `COUNT`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/issue-61522-array-len-succ.rs:12:30
@@ -13,6 +14,7 @@ LL |     fn inner(&self) -> &[u8; COUNT + 1] {
    |                              ^^^^^ cannot perform const operation using `COUNT`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `COUNT`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.min.stderr b/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.min.stderr
index 786ded3c2fe..1c2e7e069a1 100644
--- a/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.min.stderr
+++ b/src/test/ui/const-generics/issue-66596-impl-trait-for-str-const-arg.min.stderr
@@ -5,7 +5,7 @@ LL | trait Trait<const NAME: &'static str> {
    |                         ^^^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issue-67375.min.stderr b/src/test/ui/const-generics/issue-67375.min.stderr
index 3c344edbf1d..da96b5374a5 100644
--- a/src/test/ui/const-generics/issue-67375.min.stderr
+++ b/src/test/ui/const-generics/issue-67375.min.stderr
@@ -5,6 +5,7 @@ LL |     inner: [(); { [|_: &T| {}; 0].len() }],
    |                         ^ cannot perform const operation using `T`
    |
    = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error[E0392]: parameter `T` is never used
   --> $DIR/issue-67375.rs:7:12
diff --git a/src/test/ui/const-generics/issue-67945-1.min.stderr b/src/test/ui/const-generics/issue-67945-1.min.stderr
index 804236c30bd..8fea130baa5 100644
--- a/src/test/ui/const-generics/issue-67945-1.min.stderr
+++ b/src/test/ui/const-generics/issue-67945-1.min.stderr
@@ -5,6 +5,7 @@ LL |         let x: S = MaybeUninit::uninit();
    |                ^ cannot perform const operation using `S`
    |
    = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/issue-67945-1.rs:17:45
@@ -13,6 +14,7 @@ LL |         let b = &*(&x as *const _ as *const S);
    |                                             ^ cannot perform const operation using `S`
    |
    = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error[E0392]: parameter `S` is never used
   --> $DIR/issue-67945-1.rs:11:12
diff --git a/src/test/ui/const-generics/issue-67945-2.min.stderr b/src/test/ui/const-generics/issue-67945-2.min.stderr
index 2de942c1220..50633772b75 100644
--- a/src/test/ui/const-generics/issue-67945-2.min.stderr
+++ b/src/test/ui/const-generics/issue-67945-2.min.stderr
@@ -5,6 +5,7 @@ LL |         let x: S = MaybeUninit::uninit();
    |                ^ cannot perform const operation using `S`
    |
    = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/issue-67945-2.rs:15:45
@@ -13,6 +14,7 @@ LL |         let b = &*(&x as *const _ as *const S);
    |                                             ^ cannot perform const operation using `S`
    |
    = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error[E0392]: parameter `S` is never used
   --> $DIR/issue-67945-2.rs:9:12
diff --git a/src/test/ui/const-generics/issues/issue-61747.min.stderr b/src/test/ui/const-generics/issues/issue-61747.min.stderr
index b176f9d1c75..1de9e71b6eb 100644
--- a/src/test/ui/const-generics/issues/issue-61747.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-61747.min.stderr
@@ -5,6 +5,7 @@ LL |     fn successor() -> Const<{C + 1}> {
    |                              ^ cannot perform const operation using `C`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `C`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-61935.min.stderr b/src/test/ui/const-generics/issues/issue-61935.min.stderr
index 9e31466259f..b1d92056a54 100644
--- a/src/test/ui/const-generics/issues/issue-61935.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-61935.min.stderr
@@ -5,6 +5,7 @@ LL |         Self:FooImpl<{N==0}>
    |                       ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-62220.min.stderr b/src/test/ui/const-generics/issues/issue-62220.min.stderr
index 3bd127ee74a..b338cdb87e1 100644
--- a/src/test/ui/const-generics/issues/issue-62220.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-62220.min.stderr
@@ -5,6 +5,7 @@ LL | pub type TruncatedVector<T, const N: usize> = Vector<T, { N - 1 }>;
    |                                                           ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-62456.min.stderr b/src/test/ui/const-generics/issues/issue-62456.min.stderr
index c73f62a4a07..a4b501a7bb1 100644
--- a/src/test/ui/const-generics/issues/issue-62456.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-62456.min.stderr
@@ -5,6 +5,7 @@ LL |     let _ = [0u64; N + 1];
    |                    ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr b/src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr
index 6903b20fad6..5117e20d626 100644
--- a/src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr
@@ -5,7 +5,7 @@ LL | fn foo<const T: NoMatch>() -> bool {
    |                 ^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-62878.min.stderr b/src/test/ui/const-generics/issues/issue-62878.min.stderr
index 34edd09b515..9f95e5d8862 100644
--- a/src/test/ui/const-generics/issues/issue-62878.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-62878.min.stderr
@@ -11,7 +11,7 @@ LL | fn foo<const N: usize, const A: [u8; N]>() {}
    |                                 ^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr
index e6d9fb7a246..5dbfdc6d652 100644
--- a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr
@@ -5,7 +5,7 @@ LL | fn test<const T: &'static dyn A>() {
    |                  ^^^^^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error[E0741]: `&'static (dyn A + 'static)` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
   --> $DIR/issue-63322-forbid-dyn.rs:10:18
diff --git a/src/test/ui/const-generics/issues/issue-64494.min.stderr b/src/test/ui/const-generics/issues/issue-64494.min.stderr
index 8b02fd108bd..681166b1d2b 100644
--- a/src/test/ui/const-generics/issues/issue-64494.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-64494.min.stderr
@@ -5,6 +5,7 @@ LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {}
    |                                      ^^^^^^ cannot perform const operation using `T`
    |
    = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/issue-64494.rs:19:38
@@ -13,6 +14,7 @@ LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {}
    |                                      ^^^^^^ cannot perform const operation using `T`
    |
    = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error[E0119]: conflicting implementations of trait `MyTrait`:
   --> $DIR/issue-64494.rs:19:1
diff --git a/src/test/ui/const-generics/issues/issue-66205.min.stderr b/src/test/ui/const-generics/issues/issue-66205.min.stderr
index 282f72be6da..ecd96ac37e4 100644
--- a/src/test/ui/const-generics/issues/issue-66205.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-66205.min.stderr
@@ -5,6 +5,7 @@ LL |     fact::<{ N - 1 }>();
    |              ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-68366.min.stderr b/src/test/ui/const-generics/issues/issue-68366.min.stderr
index b900a0d096a..acaf4a33ee0 100644
--- a/src/test/ui/const-generics/issues/issue-68366.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-68366.min.stderr
@@ -5,6 +5,7 @@ LL | impl <const N: usize> Collatz<{Some(N)}> {}
    |                                     ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
   --> $DIR/issue-68366.rs:12:13
diff --git a/src/test/ui/const-generics/issues/issue-68615-adt.min.stderr b/src/test/ui/const-generics/issues/issue-68615-adt.min.stderr
index 81c8f4392c7..59653114a6b 100644
--- a/src/test/ui/const-generics/issues/issue-68615-adt.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-68615-adt.min.stderr
@@ -5,7 +5,7 @@ LL | struct Const<const V: [usize; 0]> {}
    |                       ^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-68615-array.min.stderr b/src/test/ui/const-generics/issues/issue-68615-array.min.stderr
index 8f55a92fce9..1ee881b96ec 100644
--- a/src/test/ui/const-generics/issues/issue-68615-array.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-68615-array.min.stderr
@@ -5,7 +5,7 @@ LL | struct Foo<const V: [usize; 0] > {}
    |                     ^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-68977.min.stderr b/src/test/ui/const-generics/issues/issue-68977.min.stderr
index 7828d859394..ea91df1e0bf 100644
--- a/src/test/ui/const-generics/issues/issue-68977.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-68977.min.stderr
@@ -5,6 +5,7 @@ LL |     PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>;
    |                 ^^^^^^^^ cannot perform const operation using `INT_BITS`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `INT_BITS`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/issue-68977.rs:29:28
@@ -13,6 +14,7 @@ LL |     PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>;
    |                            ^^^^^^^^^ cannot perform const operation using `FRAC_BITS`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `FRAC_BITS`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/issues/issue-71169.min.stderr b/src/test/ui/const-generics/issues/issue-71169.min.stderr
index 79d63443351..9b0a2946ca6 100644
--- a/src/test/ui/const-generics/issues/issue-71169.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-71169.min.stderr
@@ -11,7 +11,7 @@ LL | fn foo<const LEN: usize, const DATA: [u8; LEN]>() {}
    |                                      ^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/issues/issue-72787.min.stderr b/src/test/ui/const-generics/issues/issue-72787.min.stderr
index d960d9513b7..27bbc28011f 100644
--- a/src/test/ui/const-generics/issues/issue-72787.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-72787.min.stderr
@@ -5,6 +5,7 @@ LL |     Condition<{ LHS <= RHS }>: True
    |                 ^^^ cannot perform const operation using `LHS`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `LHS`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/issue-72787.rs:11:24
@@ -13,6 +14,7 @@ LL |     Condition<{ LHS <= RHS }>: True
    |                        ^^^ cannot perform const operation using `RHS`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `RHS`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/issue-72787.rs:26:25
@@ -21,6 +23,7 @@ LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
    |                         ^ cannot perform const operation using `I`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `I`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/issue-72787.rs:26:36
@@ -29,6 +32,7 @@ LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
    |                                    ^ cannot perform const operation using `J`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `J`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error[E0283]: type annotations needed
   --> $DIR/issue-72787.rs:22:26
diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr
index 9fec3eb946d..2394b23d799 100644
--- a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr
@@ -5,6 +5,7 @@ LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue,
    |                 ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-73491.min.stderr b/src/test/ui/const-generics/issues/issue-73491.min.stderr
index 5bf3671d38b..3ff0563acc7 100644
--- a/src/test/ui/const-generics/issues/issue-73491.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-73491.min.stderr
@@ -5,7 +5,7 @@ LL | fn hoge<const IN: [u32; LEN]>() {}
    |                   ^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-74101.min.stderr b/src/test/ui/const-generics/issues/issue-74101.min.stderr
index 8062faefbe6..1351246667e 100644
--- a/src/test/ui/const-generics/issues/issue-74101.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-74101.min.stderr
@@ -5,7 +5,7 @@ LL | fn test<const N: [u8; 1 + 2]>() {}
    |                  ^^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `[u8; _]` is forbidden as the type of a const generic parameter
   --> $DIR/issue-74101.rs:10:21
@@ -14,7 +14,7 @@ LL | struct Foo<const N: [u8; 1 + 2]>;
    |                     ^^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/issues/issue-74255.min.stderr b/src/test/ui/const-generics/issues/issue-74255.min.stderr
index 86937d715c9..e3e8502ae63 100644
--- a/src/test/ui/const-generics/issues/issue-74255.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-74255.min.stderr
@@ -5,7 +5,7 @@ LL |     fn ice_struct_fn<const I: IceEnum>() {}
    |                               ^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-74950.min.stderr b/src/test/ui/const-generics/issues/issue-74950.min.stderr
index f093e6651bc..12947a2ab37 100644
--- a/src/test/ui/const-generics/issues/issue-74950.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-74950.min.stderr
@@ -5,7 +5,7 @@ LL | struct Outer<const I: Inner>;
    |                       ^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `Inner` is forbidden as the type of a const generic parameter
   --> $DIR/issue-74950.rs:18:23
@@ -14,7 +14,7 @@ LL | struct Outer<const I: Inner>;
    |                       ^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `Inner` is forbidden as the type of a const generic parameter
   --> $DIR/issue-74950.rs:18:23
@@ -23,7 +23,7 @@ LL | struct Outer<const I: Inner>;
    |                       ^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `Inner` is forbidden as the type of a const generic parameter
   --> $DIR/issue-74950.rs:18:23
@@ -32,7 +32,7 @@ LL | struct Outer<const I: Inner>;
    |                       ^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `Inner` is forbidden as the type of a const generic parameter
   --> $DIR/issue-74950.rs:18:23
@@ -41,7 +41,7 @@ LL | struct Outer<const I: Inner>;
    |                       ^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/const-generics/issues/issue-75047.min.stderr b/src/test/ui/const-generics/issues/issue-75047.min.stderr
index edc54b082db..b87bb18a5a6 100644
--- a/src/test/ui/const-generics/issues/issue-75047.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-75047.min.stderr
@@ -5,7 +5,7 @@ LL | struct Foo<const N: [u8; Bar::<u32>::value()]>;
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr
index c10db84ea6e..551b8e43e1d 100644
--- a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr
@@ -5,6 +5,7 @@ LL | fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] {
    |                                              ^ cannot perform const operation using `T`
    |
    = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/issue-76701-ty-param-in-const.rs:12:42
@@ -13,6 +14,7 @@ LL | fn const_param<const N: usize>() -> [u8; N + 1] {
    |                                          ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/macro_rules-braces.min.stderr b/src/test/ui/const-generics/macro_rules-braces.min.stderr
index c6425edc10f..c400e2c814d 100644
--- a/src/test/ui/const-generics/macro_rules-braces.min.stderr
+++ b/src/test/ui/const-generics/macro_rules-braces.min.stderr
@@ -27,6 +27,7 @@ LL |     let _: foo!({{ N }});
    |                    ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/macro_rules-braces.rs:41:19
@@ -35,6 +36,7 @@ LL |     let _: bar!({ N });
    |                   ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/macro_rules-braces.rs:46:20
@@ -43,6 +45,7 @@ LL |     let _: baz!({{ N }});
    |                    ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/macro_rules-braces.rs:51:19
@@ -51,6 +54,7 @@ LL |     let _: biz!({ N });
    |                   ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/const-generics/min_const_generics/complex-expression.stderr b/src/test/ui/const-generics/min_const_generics/complex-expression.stderr
index a8de987e167..2ea66279d46 100644
--- a/src/test/ui/const-generics/min_const_generics/complex-expression.stderr
+++ b/src/test/ui/const-generics/min_const_generics/complex-expression.stderr
@@ -5,6 +5,7 @@ LL | struct Break0<const N: usize>([u8; { N + 1 }]);
    |                                      ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/complex-expression.rs:14:40
@@ -13,6 +14,7 @@ LL | struct Break1<const N: usize>([u8; { { N } }]);
    |                                        ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/complex-expression.rs:18:17
@@ -21,6 +23,7 @@ LL |     let _: [u8; N + 1];
    |                 ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/complex-expression.rs:23:17
@@ -29,6 +32,7 @@ LL |     let _ = [0; N + 1];
    |                 ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/complex-expression.rs:27:45
@@ -37,6 +41,7 @@ LL | struct BreakTy0<T>(T, [u8; { size_of::<*mut T>() }]);
    |                                             ^ cannot perform const operation using `T`
    |
    = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/complex-expression.rs:30:47
@@ -45,6 +50,7 @@ LL | struct BreakTy1<T>(T, [u8; { { size_of::<*mut T>() } }]);
    |                                               ^ cannot perform const operation using `T`
    |
    = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/complex-expression.rs:34:32
@@ -53,6 +59,7 @@ LL |     let _: [u8; size_of::<*mut T>() + 1];
    |                                ^ cannot perform const operation using `T`
    |
    = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 warning: cannot use constants which depend on generic parameters in types
   --> $DIR/complex-expression.rs:39:17
diff --git a/src/test/ui/const-generics/min_const_generics/complex-types.stderr b/src/test/ui/const-generics/min_const_generics/complex-types.stderr
index 52ed3c1c6ee..5d473f1f876 100644
--- a/src/test/ui/const-generics/min_const_generics/complex-types.stderr
+++ b/src/test/ui/const-generics/min_const_generics/complex-types.stderr
@@ -5,7 +5,7 @@ LL | struct Foo<const N: [u8; 0]>;
    |                     ^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `()` is forbidden as the type of a const generic parameter
   --> $DIR/complex-types.rs:7:21
@@ -14,7 +14,7 @@ LL | struct Bar<const N: ()>;
    |                     ^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `No` is forbidden as the type of a const generic parameter
   --> $DIR/complex-types.rs:12:21
@@ -23,7 +23,7 @@ LL | struct Fez<const N: No>;
    |                     ^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `&'static u8` is forbidden as the type of a const generic parameter
   --> $DIR/complex-types.rs:15:21
@@ -32,7 +32,7 @@ LL | struct Faz<const N: &'static u8>;
    |                     ^^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `!` is forbidden as the type of a const generic parameter
   --> $DIR/complex-types.rs:18:21
@@ -41,7 +41,7 @@ LL | struct Fiz<const N: !>;
    |                     ^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `()` is forbidden as the type of a const generic parameter
   --> $DIR/complex-types.rs:21:19
@@ -50,7 +50,7 @@ LL | enum Goo<const N: ()> { A, B }
    |                   ^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `()` is forbidden as the type of a const generic parameter
   --> $DIR/complex-types.rs:24:20
@@ -59,7 +59,7 @@ LL | union Boo<const N: ()> { a: () }
    |                    ^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr
index 64da5e07df2..40c73f0b951 100644
--- a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr
+++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr
@@ -5,6 +5,7 @@ LL |     fn t1() -> [u8; std::mem::size_of::<Self>()];
    |                                         ^^^^ cannot perform const operation using `Self`
    |
    = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic `Self` types are currently not permitted in anonymous constants
   --> $DIR/self-ty-in-const-1.rs:14:41
diff --git a/src/test/ui/const-generics/min_const_generics/static-reference-array-const-param.stderr b/src/test/ui/const-generics/min_const_generics/static-reference-array-const-param.stderr
index cc32d8a67fe..6c39f6b4c1d 100644
--- a/src/test/ui/const-generics/min_const_generics/static-reference-array-const-param.stderr
+++ b/src/test/ui/const-generics/min_const_generics/static-reference-array-const-param.stderr
@@ -5,7 +5,7 @@ LL | fn a<const X: &'static [u32]>() {}
    |               ^^^^^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.stderr b/src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.stderr
index 063120ad074..6b90329b72c 100644
--- a/src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.stderr
+++ b/src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.stderr
@@ -5,7 +5,7 @@ LL | struct Const<const P: &'static ()>;
    |                       ^^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/nested-type.min.stderr b/src/test/ui/const-generics/nested-type.min.stderr
index 4f76ec6e02b..369e387508e 100644
--- a/src/test/ui/const-generics/nested-type.min.stderr
+++ b/src/test/ui/const-generics/nested-type.min.stderr
@@ -12,7 +12,7 @@ LL | | }]>;
    | |__^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
   --> $DIR/nested-type.rs:16:5
diff --git a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr
index 39aa8087cec..9e0837a0a62 100644
--- a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr
+++ b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr
@@ -13,6 +13,7 @@ LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
    |                                            ^ cannot perform const operation using `T`
    |
    = note: type parameters may not be used in const expressions
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: constant values inside of type parameter defaults must not depend on generic parameters
   --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:12:21
diff --git a/src/test/ui/const-generics/slice-const-param-mismatch.min.stderr b/src/test/ui/const-generics/slice-const-param-mismatch.min.stderr
index 1f711bef4aa..46997fed770 100644
--- a/src/test/ui/const-generics/slice-const-param-mismatch.min.stderr
+++ b/src/test/ui/const-generics/slice-const-param-mismatch.min.stderr
@@ -5,7 +5,7 @@ LL | struct ConstString<const T: &'static str>;
    |                             ^^^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `&'static [u8]` is forbidden as the type of a const generic parameter
   --> $DIR/slice-const-param-mismatch.rs:10:28
@@ -14,7 +14,7 @@ LL | struct ConstBytes<const T: &'static [u8]>;
    |                            ^^^^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/slice-const-param.min.stderr b/src/test/ui/const-generics/slice-const-param.min.stderr
index 2a49619e661..7a9f65233e7 100644
--- a/src/test/ui/const-generics/slice-const-param.min.stderr
+++ b/src/test/ui/const-generics/slice-const-param.min.stderr
@@ -5,7 +5,7 @@ LL | pub fn function_with_str<const STRING: &'static str>() -> &'static str {
    |                                        ^^^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `&'static [u8]` is forbidden as the type of a const generic parameter
   --> $DIR/slice-const-param.rs:13:41
@@ -14,7 +14,7 @@ LL | pub fn function_with_bytes<const BYTES: &'static [u8]>() -> &'static [u8] {
    |                                         ^^^^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/std/const-generics-range.min.stderr b/src/test/ui/const-generics/std/const-generics-range.min.stderr
index 97be6ee6445..9274ccd2b92 100644
--- a/src/test/ui/const-generics/std/const-generics-range.min.stderr
+++ b/src/test/ui/const-generics/std/const-generics-range.min.stderr
@@ -5,7 +5,7 @@ LL | struct _Range<const R: std::ops::Range<usize>>;
    |                        ^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `RangeFrom<usize>` is forbidden as the type of a const generic parameter
   --> $DIR/const-generics-range.rs:13:28
@@ -14,7 +14,7 @@ LL | struct _RangeFrom<const R: std::ops::RangeFrom<usize>>;
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `RangeFull` is forbidden as the type of a const generic parameter
   --> $DIR/const-generics-range.rs:18:28
@@ -23,7 +23,7 @@ LL | struct _RangeFull<const R: std::ops::RangeFull>;
    |                            ^^^^^^^^^^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `RangeInclusive<usize>` is forbidden as the type of a const generic parameter
   --> $DIR/const-generics-range.rs:24:33
@@ -32,7 +32,7 @@ LL | struct _RangeInclusive<const R: std::ops::RangeInclusive<usize>>;
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `RangeTo<usize>` is forbidden as the type of a const generic parameter
   --> $DIR/const-generics-range.rs:29:26
@@ -41,7 +41,7 @@ LL | struct _RangeTo<const R: std::ops::RangeTo<usize>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `RangeToInclusive<usize>` is forbidden as the type of a const generic parameter
   --> $DIR/const-generics-range.rs:34:35
@@ -50,7 +50,7 @@ LL | struct _RangeToInclusive<const R: std::ops::RangeToInclusive<usize>>;
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/const-generics/type-dependent/issue-71348.min.stderr b/src/test/ui/const-generics/type-dependent/issue-71348.min.stderr
index 8656239605d..8f240f0d930 100644
--- a/src/test/ui/const-generics/type-dependent/issue-71348.min.stderr
+++ b/src/test/ui/const-generics/type-dependent/issue-71348.min.stderr
@@ -5,7 +5,7 @@ LL | trait Get<'a, const N: &'static str> {
    |                        ^^^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: `&'static str` is forbidden as the type of a const generic parameter
   --> $DIR/issue-71348.rs:19:25
@@ -14,7 +14,7 @@ LL |     fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Ta
    |                         ^^^^^^^^^^^^
    |
    = note: the only supported types are integers, `bool` and `char`
-   = note: more complex types are supported with `#[feature(const_generics)]`
+   = help: more complex types are supported with `#[feature(const_generics)]`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/wf-misc.min.stderr b/src/test/ui/const-generics/wf-misc.min.stderr
index 935f12dd2c3..99142cb6ce7 100644
--- a/src/test/ui/const-generics/wf-misc.min.stderr
+++ b/src/test/ui/const-generics/wf-misc.min.stderr
@@ -5,6 +5,7 @@ LL |     let _: [u8; N + 1];
    |                 ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
   --> $DIR/wf-misc.rs:17:21
@@ -13,6 +14,7 @@ LL |     let _: Const::<{N + 1}>;
    |                     ^ cannot perform const operation using `N`
    |
    = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: aborting due to 2 previous errors