diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs
index f51b0086dc8b6..8730aeb0f3bff 100644
--- a/compiler/rustc_ast/src/util/comments.rs
+++ b/compiler/rustc_ast/src/util/comments.rs
@@ -52,7 +52,10 @@ pub fn beautify_doc_string(data: Symbol, kind: CommentKind) -> Symbol {
         // when we try to compute the "horizontal trim".
         let lines = if kind == CommentKind::Block {
             // Whatever happens, we skip the first line.
-            let mut i = if lines[0].trim_start().starts_with('*') { 0 } else { 1 };
+            let mut i = lines
+                .get(0)
+                .map(|l| if l.trim_start().starts_with('*') { 0 } else { 1 })
+                .unwrap_or(0);
             let mut j = lines.len();
 
             while i < j && lines[i].trim().is_empty() {
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 28466315c8687..8340a0b360ef7 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -505,6 +505,8 @@ declare_features! (
     (active, static_nobundle, "1.16.0", Some(37403), None),
     /// Allows attributes on expressions and non-item statements.
     (active, stmt_expr_attributes, "1.6.0", Some(15701), None),
+    /// Allows lints part of the strict provenance effort.
+    (active, strict_provenance, "1.61.0", Some(95228), None),
     /// Allows the use of `#[target_feature]` on safe functions.
     (active, target_feature_11, "1.45.0", Some(69098), None),
     /// Allows using `#[thread_local]` on `static` items.
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 5704c6ed3b25d..89ce307d12cd7 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -2648,6 +2648,96 @@ declare_lint! {
     };
 }
 
+declare_lint! {
+    /// The `fuzzy_provenance_casts` lint detects an `as` cast between an integer
+    /// and a pointer.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![feature(strict_provenance)]
+    /// #![warn(fuzzy_provenance_casts)]
+    ///
+    /// fn main() {
+    ///     let _dangling = 16_usize as *const u8;
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This lint is part of the strict provenance effort, see [issue #95228].
+    /// Casting an integer to a pointer is considered bad style, as a pointer
+    /// contains, besides the *address* also a *provenance*, indicating what
+    /// memory the pointer is allowed to read/write. Casting an integer, which
+    /// doesn't have provenance, to a pointer requires the compiler to assign
+    /// (guess) provenance. The compiler assigns "all exposed valid" (see the
+    /// docs of [`ptr::from_exposed_addr`] for more information about this
+    /// "exposing"). This penalizes the optimiser and is not well suited for
+    /// dynamic analysis/dynamic program verification (e.g. Miri or CHERI
+    /// platforms).
+    ///
+    /// It is much better to use [`ptr::with_addr`] instead to specify the
+    /// provenance you want. If using this function is not possible because the
+    /// code relies on exposed provenance then there is as an escape hatch
+    /// [`ptr::from_exposed_addr`].
+    ///
+    /// [issue #95228]: https://github.com/rust-lang/rust/issues/95228
+    /// [`ptr::with_addr`]: https://doc.rust-lang.org/core/ptr/fn.with_addr
+    /// [`ptr::from_exposed_addr`]: https://doc.rust-lang.org/core/ptr/fn.from_exposed_addr
+    pub FUZZY_PROVENANCE_CASTS,
+    Allow,
+    "a fuzzy integer to pointer cast is used",
+    @feature_gate = sym::strict_provenance;
+}
+
+declare_lint! {
+    /// The `lossy_provenance_casts` lint detects an `as` cast between a pointer
+    /// and an integer.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![feature(strict_provenance)]
+    /// #![warn(lossy_provenance_casts)]
+    ///
+    /// fn main() {
+    ///     let x: u8 = 37;
+    ///     let _addr: usize = &x as *const u8 as usize;
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This lint is part of the strict provenance effort, see [issue #95228].
+    /// Casting a pointer to an integer is a lossy operation, because beyond
+    /// just an *address* a pointer may be associated with a particular
+    /// *provenance*. This information is used by the optimiser and for dynamic
+    /// analysis/dynamic program verification (e.g. Miri or CHERI platforms).
+    ///
+    /// Since this cast is lossy, it is considered good style to use the
+    /// [`ptr::addr`] method instead, which has a similar effect, but doesn't
+    /// "expose" the pointer provenance. This improves optimisation potential.
+    /// See the docs of [`ptr::addr`] and [`ptr::expose_addr`] for more information
+    /// about exposing pointer provenance.
+    ///
+    /// If your code can't comply with strict provenance and needs to expose
+    /// the provenance, then there is [`ptr::expose_addr`] as an escape hatch,
+    /// which preserves the behaviour of `as usize` casts while being explicit
+    /// about the semantics.
+    ///
+    /// [issue #95228]: https://github.com/rust-lang/rust/issues/95228
+    /// [`ptr::addr`]: https://doc.rust-lang.org/core/ptr/fn.addr
+    /// [`ptr::expose_addr`]: https://doc.rust-lang.org/core/ptr/fn.expose_addr
+    pub LOSSY_PROVENANCE_CASTS,
+    Allow,
+    "a lossy pointer to integer cast is used",
+    @feature_gate = sym::strict_provenance;
+}
+
 declare_lint! {
     /// The `const_evaluatable_unchecked` lint detects a generic constant used
     /// in a type.
@@ -3101,6 +3191,8 @@ declare_lint_pass! {
         UNSAFE_OP_IN_UNSAFE_FN,
         INCOMPLETE_INCLUDE,
         CENUM_IMPL_DROP_CAST,
+        FUZZY_PROVENANCE_CASTS,
+        LOSSY_PROVENANCE_CASTS,
         CONST_EVALUATABLE_UNCHECKED,
         INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
         MUST_NOT_SUSPEND,
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index f5803aaa0786e..dc4d10f699c75 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1348,6 +1348,7 @@ symbols! {
         str_trim,
         str_trim_end,
         str_trim_start,
+        strict_provenance,
         stringify,
         stringify_macro,
         struct_field_attributes,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 9998c5bb087e1..ac98dd5801e40 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -36,6 +36,7 @@ use rustc_span::symbol::{kw, sym};
 use rustc_span::{ExpnKind, Span, DUMMY_SP};
 use std::fmt;
 use std::iter;
+use std::ops::ControlFlow;
 
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 use crate::traits::query::normalize::AtExt as _;
@@ -2226,9 +2227,10 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
         post.dedup();
 
         if self.is_tainted_by_errors()
-            && crate_names.len() == 1
-            && ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str())
-            && spans.len() == 0
+            && (crate_names.len() == 1
+                && spans.len() == 0
+                && ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str())
+                || predicate.visit_with(&mut HasNumericInferVisitor).is_break())
         {
             // Avoid complaining about other inference issues for expressions like
             // `42 >> 1`, where the types are still `{integer}`, but we want to
@@ -2666,3 +2668,17 @@ impl ArgKind {
         }
     }
 }
+
+struct HasNumericInferVisitor;
+
+impl<'tcx> ty::TypeVisitor<'tcx> for HasNumericInferVisitor {
+    type BreakTy = ();
+
+    fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+        if matches!(ty.kind(), ty::Infer(ty::FloatVar(_) | ty::IntVar(_))) {
+            ControlFlow::Break(())
+        } else {
+            ControlFlow::CONTINUE
+        }
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index 7ce428ea12466..6091b8fee00b6 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -807,11 +807,22 @@ impl<'a, 'tcx> CastCheck<'tcx> {
 
             // ptr -> *
             (Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
-            (Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast
-            (FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast),
 
-            // * -> ptr
-            (Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast
+            // ptr-addr-cast
+            (Ptr(m_expr), Int(t_c)) => {
+                self.lossy_provenance_ptr2int_lint(fcx, t_c);
+                self.check_ptr_addr_cast(fcx, m_expr)
+            }
+            (FnPtr, Int(_)) => {
+                // FIXME(#95489): there should eventually be a lint for these casts
+                Ok(CastKind::FnPtrAddrCast)
+            }
+            // addr-ptr-cast
+            (Int(_), Ptr(mt)) => {
+                self.fuzzy_provenance_int2ptr_lint(fcx);
+                self.check_addr_ptr_cast(fcx, mt)
+            }
+            // fn-ptr-cast
             (FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
 
             // prim -> prim
@@ -973,6 +984,74 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             }
         }
     }
+
+    fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::IntTy) {
+        fcx.tcx.struct_span_lint_hir(
+            lint::builtin::LOSSY_PROVENANCE_CASTS,
+            self.expr.hir_id,
+            self.span,
+            |err| {
+                let mut err = err.build(&format!(
+                    "under strict provenance it is considered bad style to cast pointer `{}` to integer `{}`",
+                    self.expr_ty, self.cast_ty
+                ));
+
+                let msg = "use `.addr()` to obtain the address of a pointer";
+                if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
+                    let scalar_cast = match t_c {
+                        ty::cast::IntTy::U(ty::UintTy::Usize) => String::new(),
+                        _ => format!(" as {}", self.cast_ty),
+                    };
+                    err.span_suggestion(
+                        self.span,
+                        msg,
+                        format!("({}).addr(){}", snippet, scalar_cast),
+                        Applicability::MaybeIncorrect
+                    );
+                } else {
+                    err.help(msg);
+                }
+                err.help(
+                    "if you can't comply with strict provenance and need to expose the pointer\
+                    provenance you can use `.expose_addr()` instead"
+                );
+
+                err.emit();
+            },
+        );
+    }
+
+    fn fuzzy_provenance_int2ptr_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
+        fcx.tcx.struct_span_lint_hir(
+            lint::builtin::FUZZY_PROVENANCE_CASTS,
+            self.expr.hir_id,
+            self.span,
+            |err| {
+
+                let mut err = err.build(&format!(
+                    "strict provenance disallows casting integer `{}` to pointer `{}`",
+                    self.expr_ty, self.cast_ty
+                ));
+                let msg = "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address";
+                if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
+                    err.span_suggestion(
+                        self.span,
+                        msg,
+                        format!("(...).with_addr({})", snippet),
+                        Applicability::HasPlaceholders,
+                    );
+                } else {
+                    err.help(msg);
+                }
+                err.help(
+                    "if you can't comply with strict provenance and don't have a pointer with \
+                    the correct provenance you can use `std::ptr::from_exposed_addr()` instead"
+                 );
+
+                err.emit();
+            },
+        );
+    }
 }
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
diff --git a/library/core/src/macros/panic.md b/library/core/src/macros/panic.md
index d8206e7893114..98fb7e9e41d7a 100644
--- a/library/core/src/macros/panic.md
+++ b/library/core/src/macros/panic.md
@@ -24,20 +24,30 @@ See also the macro [`compile_error!`], for raising errors during compilation.
 
 # When to use `panic!` vs `Result`
 
-The Rust model of error handling groups errors into two major categories:
-recoverable and unrecoverable errors. For a recoverable error, such as a file
-not found error, it’s reasonable to report the problem to the user and retry
-the operation. Unrecoverable errors are always symptoms of bugs, like trying to
-access a location beyond the end of an array.
+The Rust language provides two complementary systems for constructing /
+representing, reporting, propagating, reacting to, and discarding errors. These
+responsibilities are collectively known as "error handling." `panic!` and
+`Result` are similar in that they are each the primary interface of their
+respective error handling systems; however, the meaning these interfaces attach
+to their errors and the responsibilities they fulfill within their respective
+error handling systems differ.
 
-The Rust language and standard library provides `Result` and `panic!` as parts
-of two complementary systems for representing, reporting, propagating, reacting
-to, and discarding errors for in these two categories.
+The `panic!` macro is used to construct errors that represent a bug that has
+been detected in your program. With `panic!` you provide a message that
+describes the bug and the language then constructs an error with that message,
+reports it, and propagates it for you.
 
-The `panic!` macro is provided to represent unrecoverable errors, whereas the
-`Result` enum is provided to represent recoverable errors. For more detailed
-information about error handling check out the [book] or the [`std::result`]
-module docs.
+`Result` on the other hand is used to wrap other types that represent either
+the successful result of some computation, `Ok(T)`, or error types that
+represent an anticipated runtime failure mode of that computation, `Err(E)`.
+`Result` is used alongside user defined types which represent the various
+anticipated runtime failure modes that the associated computation could
+encounter. `Result` must be propagated manually, often with the the help of the
+`?` operator and `Try` trait, and they must be reported manually, often with
+the help of the `Error` trait.
+
+For more detailed information about error handling check out the [book] or the
+[`std::result`] module docs.
 
 [ounwrap]: Option::unwrap
 [runwrap]: Result::unwrap
diff --git a/src/doc/unstable-book/src/language-features/strict-provenance.md b/src/doc/unstable-book/src/language-features/strict-provenance.md
new file mode 100644
index 0000000000000..dc60f3f375d3c
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/strict-provenance.md
@@ -0,0 +1,22 @@
+# `strict_provenance`
+
+The tracking issue for this feature is: [#95228]
+
+[#95228]: https://github.com/rust-lang/rust/issues/95228
+-----
+
+The `strict_provenance` feature allows to enable the `fuzzy_provenance_casts` and `lossy_provenance_casts` lints.
+These lint on casts between integers and pointers, that are recommended against or invalid in the strict provenance model.
+The same feature gate is also used for the experimental strict provenance API in `std` (actually `core`).
+
+## Example
+
+```rust
+#![feature(strict_provenance)]
+#![warn(fuzzy_provenance_casts)]
+
+fn main() {
+    let _dangling = 16_usize as *const u8;
+    //~^ WARNING: strict provenance disallows casting integer `usize` to pointer `*const u8`
+}
+```
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 5c59609d5b8c6..228976cb171b5 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -371,7 +371,8 @@ crate fn print_where_clause<'a, 'tcx: 'a>(
             clause = clause.replace("<br>", &format!("<br>{}", padding));
             clause.insert_str(0, &"&nbsp;".repeat(indent.saturating_sub(1)));
             if !end_newline {
-                clause.insert_str(0, "<br>");
+                // we insert the <br> after a single space but before multiple spaces at the start
+                clause.insert_str(if indent == 0 { 1 } else { 0 }, "<br>");
             }
         }
         write!(f, "{}", clause)
diff --git a/src/test/rustdoc/empty-doc-comment.rs b/src/test/rustdoc/empty-doc-comment.rs
new file mode 100644
index 0000000000000..b1dae930e066b
--- /dev/null
+++ b/src/test/rustdoc/empty-doc-comment.rs
@@ -0,0 +1,22 @@
+// Ensure that empty doc comments don't panic.
+
+/*!
+*/
+
+///
+///
+pub struct Foo;
+
+#[doc = "
+"]
+pub mod Mod {
+   //!
+   //!
+}
+
+/**
+*/
+pub mod Another {
+   #![doc = "
+"]
+}
diff --git a/src/test/rustdoc/where.SWhere_Simd_item-decl.html b/src/test/rustdoc/where.SWhere_Simd_item-decl.html
new file mode 100644
index 0000000000000..d941ad7de4c48
--- /dev/null
+++ b/src/test/rustdoc/where.SWhere_Simd_item-decl.html
@@ -0,0 +1 @@
+<div class="docblock item-decl"><pre class="rust struct"><code>pub struct Simd&lt;T, const LANES:&#160;<a class="primitive" href="https://doc.rust-lang.org/nightly/std/primitive.usize.html">usize</a>&gt;(_) <br /><span class="where">where<br />&#160;&#160;&#160;&#160;T: <a class="trait" href="https://doc.rust-lang.org/nightly/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span>;</code></pre></div>
\ No newline at end of file
diff --git a/src/test/rustdoc/where.SWhere_TraitWhere_item-decl.html b/src/test/rustdoc/where.SWhere_TraitWhere_item-decl.html
new file mode 100644
index 0000000000000..54026ff034e00
--- /dev/null
+++ b/src/test/rustdoc/where.SWhere_TraitWhere_item-decl.html
@@ -0,0 +1,3 @@
+<div class="docblock item-decl"><pre class="rust trait"><code>pub trait TraitWhere {
+    type <a href="#associatedtype.Item" class="associatedtype">Item</a>&lt;'a&gt;<br />&#160;&#160;&#160; <span class="where">where<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Self: 'a</span>;
+}</code></pre></div>
\ No newline at end of file
diff --git a/src/test/rustdoc/where.rs b/src/test/rustdoc/where.rs
index 549cfff96cb6d..73c75fdb61bcd 100644
--- a/src/test/rustdoc/where.rs
+++ b/src/test/rustdoc/where.rs
@@ -1,3 +1,4 @@
+#![feature(generic_associated_types)]
 #![crate_name = "foo"]
 
 pub trait MyTrait { fn dummy(&self) { } }
@@ -19,6 +20,18 @@ impl<D> Delta<D> where D: MyTrait {
 
 pub struct Echo<E>(E);
 
+// @has 'foo/struct.Simd.html'
+// @snapshot SWhere_Simd_item-decl - '//div[@class="docblock item-decl"]'
+pub struct Simd<T, const LANES: usize>([T; LANES])
+where
+    T: Sized;
+
+// @has 'foo/trait.TraitWhere.html'
+// @snapshot SWhere_TraitWhere_item-decl - '//div[@class="docblock item-decl"]'
+pub trait TraitWhere {
+    type Item<'a> where Self: 'a;
+}
+
 // @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
 //          "impl<E> MyTrait for Echo<E> where E: MyTrait"
 // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header in-band"]' \
diff --git a/src/test/ui/feature-gates/feature-gate-strict_provenance.rs b/src/test/ui/feature-gates/feature-gate-strict_provenance.rs
new file mode 100644
index 0000000000000..75d0ee5700d07
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-strict_provenance.rs
@@ -0,0 +1,19 @@
+// check-pass
+
+#![deny(fuzzy_provenance_casts)]
+//~^ WARNING unknown lint: `fuzzy_provenance_casts`
+//~| WARNING unknown lint: `fuzzy_provenance_casts`
+//~| WARNING unknown lint: `fuzzy_provenance_casts`
+#![deny(lossy_provenance_casts)]
+//~^ WARNING unknown lint: `lossy_provenance_casts`
+//~| WARNING unknown lint: `lossy_provenance_casts`
+//~| WARNING unknown lint: `lossy_provenance_casts`
+
+fn main() {
+    // no warnings emitted since the lints are not activated
+
+    let _dangling = 16_usize as *const u8;
+
+    let x: u8 = 37;
+    let _addr: usize = &x as *const u8 as usize;
+}
diff --git a/src/test/ui/feature-gates/feature-gate-strict_provenance.stderr b/src/test/ui/feature-gates/feature-gate-strict_provenance.stderr
new file mode 100644
index 0000000000000..34bd240c304a7
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-strict_provenance.stderr
@@ -0,0 +1,63 @@
+warning: unknown lint: `fuzzy_provenance_casts`
+  --> $DIR/feature-gate-strict_provenance.rs:3:1
+   |
+LL | #![deny(fuzzy_provenance_casts)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(unknown_lints)]` on by default
+   = note: the `fuzzy_provenance_casts` lint is unstable
+   = note: see issue #95228 <https://github.com/rust-lang/rust/issues/95228> for more information
+   = help: add `#![feature(strict_provenance)]` to the crate attributes to enable
+
+warning: unknown lint: `lossy_provenance_casts`
+  --> $DIR/feature-gate-strict_provenance.rs:7:1
+   |
+LL | #![deny(lossy_provenance_casts)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `lossy_provenance_casts` lint is unstable
+   = note: see issue #95228 <https://github.com/rust-lang/rust/issues/95228> for more information
+   = help: add `#![feature(strict_provenance)]` to the crate attributes to enable
+
+warning: unknown lint: `fuzzy_provenance_casts`
+  --> $DIR/feature-gate-strict_provenance.rs:3:1
+   |
+LL | #![deny(fuzzy_provenance_casts)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `fuzzy_provenance_casts` lint is unstable
+   = note: see issue #95228 <https://github.com/rust-lang/rust/issues/95228> for more information
+   = help: add `#![feature(strict_provenance)]` to the crate attributes to enable
+
+warning: unknown lint: `lossy_provenance_casts`
+  --> $DIR/feature-gate-strict_provenance.rs:7:1
+   |
+LL | #![deny(lossy_provenance_casts)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `lossy_provenance_casts` lint is unstable
+   = note: see issue #95228 <https://github.com/rust-lang/rust/issues/95228> for more information
+   = help: add `#![feature(strict_provenance)]` to the crate attributes to enable
+
+warning: unknown lint: `fuzzy_provenance_casts`
+  --> $DIR/feature-gate-strict_provenance.rs:3:1
+   |
+LL | #![deny(fuzzy_provenance_casts)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `fuzzy_provenance_casts` lint is unstable
+   = note: see issue #95228 <https://github.com/rust-lang/rust/issues/95228> for more information
+   = help: add `#![feature(strict_provenance)]` to the crate attributes to enable
+
+warning: unknown lint: `lossy_provenance_casts`
+  --> $DIR/feature-gate-strict_provenance.rs:7:1
+   |
+LL | #![deny(lossy_provenance_casts)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `lossy_provenance_casts` lint is unstable
+   = note: see issue #95228 <https://github.com/rust-lang/rust/issues/95228> for more information
+   = help: add `#![feature(strict_provenance)]` to the crate attributes to enable
+
+warning: 6 warnings emitted
+
diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
index a1cfee944c8bd..98fd13553c009 100644
--- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
+++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
@@ -104,6 +104,32 @@ fn main() {
             "attempted to instantiate uninhabited type `Bar`"
         );
 
+        test_panic_msg(
+            || mem::uninitialized::<[Foo; 2]>(),
+            "attempted to instantiate uninhabited type `[Foo; 2]`"
+        );
+        test_panic_msg(
+            || mem::zeroed::<[Foo; 2]>(),
+            "attempted to instantiate uninhabited type `[Foo; 2]`"
+        );
+        test_panic_msg(
+            || MaybeUninit::<[Foo; 2]>::uninit().assume_init(),
+            "attempted to instantiate uninhabited type `[Foo; 2]`"
+        );
+
+        test_panic_msg(
+            || mem::uninitialized::<[Bar; 2]>(),
+            "attempted to instantiate uninhabited type `[Bar; 2]`"
+        );
+        test_panic_msg(
+            || mem::zeroed::<[Bar; 2]>(),
+            "attempted to instantiate uninhabited type `[Bar; 2]`"
+        );
+        test_panic_msg(
+            || MaybeUninit::<[Bar; 2]>::uninit().assume_init(),
+            "attempted to instantiate uninhabited type `[Bar; 2]`"
+        );
+
         // Types that do not like zero-initialziation
         test_panic_msg(
             || mem::uninitialized::<fn()>(),
@@ -199,7 +225,9 @@ fn main() {
         let _val = mem::zeroed::<OneVariant>();
         let _val = mem::zeroed::<Option<&'static i32>>();
         let _val = mem::zeroed::<MaybeUninit<NonNull<u32>>>();
+        let _val = mem::zeroed::<[!; 0]>();
         let _val = mem::uninitialized::<MaybeUninit<bool>>();
+        let _val = mem::uninitialized::<[!; 0]>();
 
         // These are UB because they have not been officially blessed, but we await the resolution
         // of <https://github.com/rust-lang/unsafe-code-guidelines/issues/71> before doing
diff --git a/src/test/ui/lint/lint-strict-provenance-fuzzy-casts.rs b/src/test/ui/lint/lint-strict-provenance-fuzzy-casts.rs
new file mode 100644
index 0000000000000..d2d72a68f1396
--- /dev/null
+++ b/src/test/ui/lint/lint-strict-provenance-fuzzy-casts.rs
@@ -0,0 +1,7 @@
+#![feature(strict_provenance)]
+#![deny(fuzzy_provenance_casts)]
+
+fn main() {
+    let dangling = 16_usize as *const u8;
+    //~^ ERROR strict provenance disallows casting integer `usize` to pointer `*const u8`
+}
diff --git a/src/test/ui/lint/lint-strict-provenance-fuzzy-casts.stderr b/src/test/ui/lint/lint-strict-provenance-fuzzy-casts.stderr
new file mode 100644
index 0000000000000..e50d243b6ad6d
--- /dev/null
+++ b/src/test/ui/lint/lint-strict-provenance-fuzzy-casts.stderr
@@ -0,0 +1,19 @@
+error: strict provenance disallows casting integer `usize` to pointer `*const u8`
+  --> $DIR/lint-strict-provenance-fuzzy-casts.rs:5:20
+   |
+LL |     let dangling = 16_usize as *const u8;
+   |                    ^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/lint-strict-provenance-fuzzy-casts.rs:2:9
+   |
+LL | #![deny(fuzzy_provenance_casts)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   = help: if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::from_exposed_addr()` instead
+help: use `.with_addr()` to adjust a valid pointer in the same allocation, to this address
+   |
+LL |     let dangling = (...).with_addr(16_usize);
+   |                    ~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lint/lint-strict-provenance-lossy-casts.rs b/src/test/ui/lint/lint-strict-provenance-lossy-casts.rs
new file mode 100644
index 0000000000000..3690fbc904d99
--- /dev/null
+++ b/src/test/ui/lint/lint-strict-provenance-lossy-casts.rs
@@ -0,0 +1,11 @@
+#![feature(strict_provenance)]
+#![deny(lossy_provenance_casts)]
+
+fn main() {
+    let x: u8 = 37;
+    let addr: usize = &x as *const u8 as usize;
+    //~^ ERROR under strict provenance it is considered bad style to cast pointer `*const u8` to integer `usize`
+
+    let addr_32bit = &x as *const u8 as u32;
+    //~^ ERROR under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32`
+}
diff --git a/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr b/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr
new file mode 100644
index 0000000000000..489cb03ddd316
--- /dev/null
+++ b/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr
@@ -0,0 +1,23 @@
+error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `usize`
+  --> $DIR/lint-strict-provenance-lossy-casts.rs:6:23
+   |
+LL |     let addr: usize = &x as *const u8 as usize;
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.addr()` to obtain the address of a pointer: `(&x as *const u8).addr()`
+   |
+note: the lint level is defined here
+  --> $DIR/lint-strict-provenance-lossy-casts.rs:2:9
+   |
+LL | #![deny(lossy_provenance_casts)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   = help: if you can't comply with strict provenance and need to expose the pointerprovenance you can use `.expose_addr()` instead
+
+error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32`
+  --> $DIR/lint-strict-provenance-lossy-casts.rs:9:22
+   |
+LL |     let addr_32bit = &x as *const u8 as u32;
+   |                      ^^^^^^^^^^^^^^^^^^^^^^ help: use `.addr()` to obtain the address of a pointer: `(&x as *const u8).addr() as u32`
+   |
+   = help: if you can't comply with strict provenance and need to expose the pointerprovenance you can use `.expose_addr()` instead
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/traits/no-fallback-multiple-impls.rs b/src/test/ui/traits/no-fallback-multiple-impls.rs
new file mode 100644
index 0000000000000..7ed3796f08b76
--- /dev/null
+++ b/src/test/ui/traits/no-fallback-multiple-impls.rs
@@ -0,0 +1,16 @@
+trait Fallback {
+    fn foo(&self) {}
+}
+
+impl Fallback for i32 {}
+
+impl Fallback for u64 {}
+
+impl Fallback for usize {}
+
+fn main() {
+    missing();
+    //~^ ERROR cannot find function `missing` in this scope
+    0.foo();
+    // But then we shouldn't report an inference ambiguity here...
+}
diff --git a/src/test/ui/traits/no-fallback-multiple-impls.stderr b/src/test/ui/traits/no-fallback-multiple-impls.stderr
new file mode 100644
index 0000000000000..61c9e5aaabdb4
--- /dev/null
+++ b/src/test/ui/traits/no-fallback-multiple-impls.stderr
@@ -0,0 +1,9 @@
+error[E0425]: cannot find function `missing` in this scope
+  --> $DIR/no-fallback-multiple-impls.rs:12:5
+   |
+LL |     missing();
+   |     ^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/traits/test-2.rs b/src/test/ui/traits/test-2.rs
index d062de25ac8c1..342928e882a55 100644
--- a/src/test/ui/traits/test-2.rs
+++ b/src/test/ui/traits/test-2.rs
@@ -6,9 +6,9 @@ impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah<X>(&self) {} }
 impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah<X>(&self) {} }
 
 fn main() {
-    10.dup::<i32>(); //~ ERROR type annotations needed
+    10.dup::<i32>();
     //~^ ERROR this associated function takes 0 generic arguments but 1
-    10.blah::<i32, i32>(); //~ ERROR type annotations needed
+    10.blah::<i32, i32>();
     //~^ ERROR this associated function takes 1 generic argument but 2
     (Box::new(10) as Box<dyn bar>).dup();
     //~^ ERROR E0038
diff --git a/src/test/ui/traits/test-2.stderr b/src/test/ui/traits/test-2.stderr
index 5eec012458450..77ea4e4e974eb 100644
--- a/src/test/ui/traits/test-2.stderr
+++ b/src/test/ui/traits/test-2.stderr
@@ -79,35 +79,7 @@ LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
    = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn bar>>` for `Box<{integer}>`
    = note: required by cast to type `Box<dyn bar>`
 
-error[E0283]: type annotations needed
-  --> $DIR/test-2.rs:9:8
-   |
-LL |     10.dup::<i32>();
-   |        ^^^ cannot infer type for type `{integer}`
-   |
-note: multiple `impl`s satisfying `{integer}: bar` found
-  --> $DIR/test-2.rs:5:1
-   |
-LL | impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah<X>(&self) {} }
-   | ^^^^^^^^^^^^^^^^
-LL | impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah<X>(&self) {} }
-   | ^^^^^^^^^^^^^^^^
-
-error[E0283]: type annotations needed
-  --> $DIR/test-2.rs:11:8
-   |
-LL |     10.blah::<i32, i32>();
-   |        ^^^^ cannot infer type for type `{integer}`
-   |
-note: multiple `impl`s satisfying `{integer}: bar` found
-  --> $DIR/test-2.rs:5:1
-   |
-LL | impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah<X>(&self) {} }
-   | ^^^^^^^^^^^^^^^^
-LL | impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah<X>(&self) {} }
-   | ^^^^^^^^^^^^^^^^
-
-error: aborting due to 7 previous errors
+error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0038, E0107, E0283.
+Some errors have detailed explanations: E0038, E0107.
 For more information about an error, try `rustc --explain E0038`.