diff --git a/RELEASES.md b/RELEASES.md
index 0965e37574d07..0e118fb939ff0 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,129 @@
+Version 1.61.0 (2022-05-19)
+==========================
+
+Language
+--------
+
+- [`const fn` signatures can now include generic trait bounds][93827]
+- [`const fn` signatures can now use `impl Trait` in argument and return position][93827]
+- [Function pointers can now be created, cast, and passed around in a `const fn`][93827]
+- [Recursive calls can now set the value of a function's opaque `impl Trait` return type][94081]
+
+Compiler
+--------
+
+- [Linking modifier syntax in `#[link]` attributes and on the command line, as well as the `whole-archive` modifier specifically, are now supported][93901]
+- [The `char` type is now described as UTF-32 in debuginfo][89887]
+- The [`#[target_feature]`][target_feature] attribute [can now be used with aarch64 features][90621]
+- X86 [`#[target_feature = "adx"]` is now stable][93745]
+
+Libraries
+---------
+
+- [`ManuallyDrop<T>` is now documented to have the same layout as `T`][88375]
+- [`#[ignore = "…"]` messages are printed when running tests][92714]
+- [Consistently show absent stdio handles on Windows as NULL handles][93263]
+- [Make `std::io::stdio::lock()` return `'static` handles.][93965] Previously, the creation of locked handles to stdin/stdout/stderr would borrow the handles being locked, which prevented writing `let out = std::io::stdout().lock();` because `out` would outlive the return value of `stdout()`. Such code now works, eliminating a common pitfall that affected many Rust users.
+- [`Vec::from_raw_parts` is now less restrictive about its inputs][95016]
+- [`std::thread::available_parallelism` now takes cgroup quotas into account.][92697] Since `available_parallelism` is often used to create a thread pool for parallel computation, which may be CPU-bound for performance, `available_parallelism` will return a value consistent with the ability to use that many threads continuously, if possible. For instance, in a container with 8 virtual CPUs but quotas only allowing for 50% usage, `available_parallelism` will return 4.
+
+Stabilized APIs
+---------------
+
+- [`Pin::static_mut`]
+- [`Pin::static_ref`]
+- [`Vec::retain_mut`]
+- [`VecDeque::retain_mut`]
+- [`Write` for `Cursor<[u8; N]>`][cursor-write-array]
+- [`std::os::unix::net::SocketAddr::from_pathname`]
+- [`std::process::ExitCode`] and [`std::process::Termination`]. The stabilization of these two APIs now makes it possible for programs to return errors from `main` with custom exit codes.
+- [`std::thread::JoinHandle::is_finished`]
+
+These APIs are now usable in const contexts:
+
+- [`<*const T>::offset` and `<*mut T>::offset`][ptr-offset]
+- [`<*const T>::wrapping_offset` and `<*mut T>::wrapping_offset`][ptr-wrapping_offset]
+- [`<*const T>::add` and `<*mut T>::add`][ptr-add]
+- [`<*const T>::sub` and `<*mut T>::sub`][ptr-sub]
+- [`<*const T>::wrapping_add` and `<*mut T>::wrapping_add`][ptr-wrapping_add]
+- [`<*const T>::wrapping_sub` and `<*mut T>::wrapping_sub`][ptr-wrapping_sub]
+- [`<[T]>::as_mut_ptr`][slice-as_mut_ptr]
+- [`<[T]>::as_ptr_range`][slice-as_ptr_range]
+- [`<[T]>::as_mut_ptr_range`][slice-as_mut_ptr_range]
+
+Cargo
+-----
+
+No feature changes, but see compatibility notes.
+
+Compatibility Notes
+-------------------
+
+- Previously native static libraries were linked as `whole-archive` in some cases, but now rustc tries not to use `whole-archive` unless explicitly requested. This [change][93901] may result in linking errors in some cases. To fix such errors, native libraries linked from the command line, build scripts, or [`#[link]` attributes][link-attr] need to
+  - (more common) either be reordered to respect dependencies between them (if `a` depends on `b` then `a` should go first and `b` second)
+  - (less common) or be updated to use the [`+whole-archive`] modifier.
+- [Catching a second unwind from FFI code while cleaning up from a Rust panic now causes the process to abort][92911]
+- [Proc macros no longer see `ident` matchers wrapped in groups][92472]
+- [The number of `#` in `r#` raw string literals is now required to be less than 256][95251]
+- [When checking that a dyn type satisfies a trait bound, supertrait bounds are now enforced][92285]
+- [`cargo vendor` now only accepts one value for each `--sync` flag][cargo/10448]
+- [`cfg` predicates in `all()` and `any()` are always evaluated to detect errors, instead of short-circuiting.][94295] The compatibility considerations here arise in nightly-only code that used the short-circuiting behavior of `all` to write something like `cfg(all(feature = "nightly", syntax-requiring-nightly))`, which will now fail to compile. Instead, use either `cfg_attr(feature = "nightly", ...)` or nested uses of `cfg`.
+- [bootstrap: static-libstdcpp is now enabled by default, and can now be disabled when llvm-tools is enabled][94832]
+
+Internal Changes
+----------------
+
+These changes provide no direct user facing benefits, but represent significant
+improvements to the internals and overall performance of rustc
+and related tools.
+
+- [debuginfo: Refactor debuginfo generation for types][94261]
+- [Remove the everybody loops pass][93913]
+
+[88375]: https://github.com/rust-lang/rust/pull/88375/
+[89887]: https://github.com/rust-lang/rust/pull/89887/
+[90621]: https://github.com/rust-lang/rust/pull/90621/
+[92285]: https://github.com/rust-lang/rust/pull/92285/
+[92472]: https://github.com/rust-lang/rust/pull/92472/
+[92697]: https://github.com/rust-lang/rust/pull/92697/
+[92714]: https://github.com/rust-lang/rust/pull/92714/
+[92911]: https://github.com/rust-lang/rust/pull/92911/
+[93263]: https://github.com/rust-lang/rust/pull/93263/
+[93745]: https://github.com/rust-lang/rust/pull/93745/
+[93827]: https://github.com/rust-lang/rust/pull/93827/
+[93901]: https://github.com/rust-lang/rust/pull/93901/
+[93913]: https://github.com/rust-lang/rust/pull/93913/
+[93965]: https://github.com/rust-lang/rust/pull/93965/
+[94081]: https://github.com/rust-lang/rust/pull/94081/
+[94261]: https://github.com/rust-lang/rust/pull/94261/
+[94295]: https://github.com/rust-lang/rust/pull/94295/
+[94832]: https://github.com/rust-lang/rust/pull/94832/
+[95016]: https://github.com/rust-lang/rust/pull/95016/
+[95251]: https://github.com/rust-lang/rust/pull/95251/
+[`+whole-archive`]: https://doc.rust-lang.org/stable/rustc/command-line-arguments.html#linking-modifiers-whole-archive
+[`Pin::static_mut`]: https://doc.rust-lang.org/stable/std/pin/struct.Pin.html#method.static_mut
+[`Pin::static_ref`]: https://doc.rust-lang.org/stable/std/pin/struct.Pin.html#method.static_ref
+[`Vec::retain_mut`]: https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.retain_mut
+[`VecDeque::retain_mut`]: https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.retain_mut
+[`std::os::unix::net::SocketAddr::from_pathname`]: https://doc.rust-lang.org/stable/std/os/unix/net/struct.SocketAddr.html#method.from_pathname
+[`std::process::ExitCode`]: https://doc.rust-lang.org/stable/std/process/struct.ExitCode.html
+[`std::process::Termination`]: https://doc.rust-lang.org/stable/std/process/trait.Termination.html
+[`std::thread::JoinHandle::is_finished`]: https://doc.rust-lang.org/stable/std/thread/struct.JoinHandle.html#method.is_finished
+[cargo/10448]: https://github.com/rust-lang/cargo/pull/10448/
+[cursor-write-array]: https://doc.rust-lang.org/stable/std/io/struct.Cursor.html#impl-Write-4
+[link-attr]: https://doc.rust-lang.org/stable/reference/items/external-blocks.html#the-link-attribute
+[ptr-add]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.add
+[ptr-offset]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset
+[ptr-sub]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.sub
+[ptr-wrapping_add]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.wrapping_add
+[ptr-wrapping_offset]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.wrapping_offset
+[ptr-wrapping_sub]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.wrapping_sub
+[slice-as_mut_ptr]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_mut_ptr
+[slice-as_mut_ptr_range]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_mut_ptr_range
+[slice-as_ptr_range]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_ptr_range
+[target_feature]: https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute
+
+
 Version 1.60.0 (2022-04-07)
 ==========================
 
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index a73fd13ce2d0e..85b7fb5eb25fc 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -554,7 +554,8 @@ impl<'tcx> Inliner<'tcx> {
                     new_scopes: SourceScope::new(caller_body.source_scopes.len())..,
                     new_blocks: BasicBlock::new(caller_body.basic_blocks().len())..,
                     destination: dest,
-                    return_block: callsite.target,
+                    callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(),
+                    callsite,
                     cleanup_block: cleanup,
                     in_cleanup_block: false,
                     tcx: self.tcx,
@@ -566,31 +567,6 @@ impl<'tcx> Inliner<'tcx> {
                 // (or existing ones, in a few special cases) in the caller.
                 integrator.visit_body(&mut callee_body);
 
-                for scope in &mut callee_body.source_scopes {
-                    // FIXME(eddyb) move this into a `fn visit_scope_data` in `Integrator`.
-                    if scope.parent_scope.is_none() {
-                        let callsite_scope = &caller_body.source_scopes[callsite.source_info.scope];
-
-                        // Attach the outermost callee scope as a child of the callsite
-                        // scope, via the `parent_scope` and `inlined_parent_scope` chains.
-                        scope.parent_scope = Some(callsite.source_info.scope);
-                        assert_eq!(scope.inlined_parent_scope, None);
-                        scope.inlined_parent_scope = if callsite_scope.inlined.is_some() {
-                            Some(callsite.source_info.scope)
-                        } else {
-                            callsite_scope.inlined_parent_scope
-                        };
-
-                        // Mark the outermost callee scope as an inlined one.
-                        assert_eq!(scope.inlined, None);
-                        scope.inlined = Some((callsite.callee, callsite.source_info.span));
-                    } else if scope.inlined_parent_scope.is_none() {
-                        // Make it easy to find the scope with `inlined` set above.
-                        scope.inlined_parent_scope =
-                            Some(integrator.map_scope(OUTERMOST_SOURCE_SCOPE));
-                    }
-                }
-
                 // If there are any locals without storage markers, give them storage only for the
                 // duration of the call.
                 for local in callee_body.vars_and_temps_iter() {
@@ -786,7 +762,8 @@ struct Integrator<'a, 'tcx> {
     new_scopes: RangeFrom<SourceScope>,
     new_blocks: RangeFrom<BasicBlock>,
     destination: Place<'tcx>,
-    return_block: Option<BasicBlock>,
+    callsite_scope: SourceScopeData<'tcx>,
+    callsite: &'a CallSite<'tcx>,
     cleanup_block: Option<BasicBlock>,
     in_cleanup_block: bool,
     tcx: TyCtxt<'tcx>,
@@ -832,6 +809,28 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
         *local = self.map_local(*local);
     }
 
+    fn visit_source_scope_data(&mut self, scope_data: &mut SourceScopeData<'tcx>) {
+        self.super_source_scope_data(scope_data);
+        if scope_data.parent_scope.is_none() {
+            // Attach the outermost callee scope as a child of the callsite
+            // scope, via the `parent_scope` and `inlined_parent_scope` chains.
+            scope_data.parent_scope = Some(self.callsite.source_info.scope);
+            assert_eq!(scope_data.inlined_parent_scope, None);
+            scope_data.inlined_parent_scope = if self.callsite_scope.inlined.is_some() {
+                Some(self.callsite.source_info.scope)
+            } else {
+                self.callsite_scope.inlined_parent_scope
+            };
+
+            // Mark the outermost callee scope as an inlined one.
+            assert_eq!(scope_data.inlined, None);
+            scope_data.inlined = Some((self.callsite.callee, self.callsite.source_info.span));
+        } else if scope_data.inlined_parent_scope.is_none() {
+            // Make it easy to find the scope with `inlined` set above.
+            scope_data.inlined_parent_scope = Some(self.map_scope(OUTERMOST_SOURCE_SCOPE));
+        }
+    }
+
     fn visit_source_scope(&mut self, scope: &mut SourceScope) {
         *scope = self.map_scope(*scope);
     }
@@ -938,7 +937,7 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
                 }
             }
             TerminatorKind::Return => {
-                terminator.kind = if let Some(tgt) = self.return_block {
+                terminator.kind = if let Some(tgt) = self.callsite.target {
                     TerminatorKind::Goto { target: tgt }
                 } else {
                     TerminatorKind::Unreachable
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index a153997599aba..d9aaf730efcc4 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -347,16 +347,22 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 );
                 err.span_label(self.span, "invalid cast");
                 if self.expr_ty.is_numeric() {
-                    err.span_help(
-                        self.span,
-                        if self.expr_ty == fcx.tcx.types.i8 {
-                            "try casting from `u8` instead"
-                        } else if self.expr_ty == fcx.tcx.types.u32 {
-                            "try `char::from_u32` instead"
-                        } else {
-                            "try `char::from_u32` instead (via a `u32`)"
-                        },
-                    );
+                    if self.expr_ty == fcx.tcx.types.u32 {
+                        match fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
+                            Ok(snippet) => err.span_suggestion(
+                                self.span,
+                                "try `char::from_u32` instead",
+                                format!("char::from_u32({snippet})"),
+                                Applicability::MachineApplicable,
+                            ),
+
+                            Err(_) => err.span_help(self.span, "try `char::from_u32` instead"),
+                        };
+                    } else if self.expr_ty == fcx.tcx.types.i8 {
+                        err.span_help(self.span, "try casting from `u8` instead");
+                    } else {
+                        err.span_help(self.span, "try `char::from_u32` instead (via a `u32`)");
+                    };
                 }
                 err.emit();
             }
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index a01f3fbad565c..36df5c3beb30a 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -2830,7 +2830,7 @@ unsafe fn atomic_umin<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 /// A fence 'A' which has (at least) [`Release`] ordering semantics, synchronizes
 /// with a fence 'B' with (at least) [`Acquire`] semantics, if and only if there
 /// exist operations X and Y, both operating on some atomic object 'M' such
-/// that A is sequenced before X, Y is synchronized before B and Y observes
+/// that A is sequenced before X, Y is sequenced before B and Y observes
 /// the change to M. This provides a happens-before dependence between A and B.
 ///
 /// ```text
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index e253f46406fb7..28e802d07e197 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -2136,7 +2136,7 @@ pub trait Termination {
 impl Termination for () {
     #[inline]
     fn report(self) -> ExitCode {
-        ExitCode::SUCCESS.report()
+        ExitCode::SUCCESS
     }
 }
 
@@ -2162,7 +2162,7 @@ impl<E: fmt::Debug> Termination for Result<!, E> {
     fn report(self) -> ExitCode {
         let Err(err) = self;
         eprintln!("Error: {err:?}");
-        ExitCode::FAILURE.report()
+        ExitCode::FAILURE
     }
 }
 
diff --git a/src/test/ui/const-generics/issues/issue-88119.rs b/src/test/ui/const-generics/issues/issue-88119.rs
new file mode 100644
index 0000000000000..70dfa7f708b4f
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-88119.rs
@@ -0,0 +1,35 @@
+// check-pass
+
+#![allow(incomplete_features)]
+#![feature(const_trait_impl, generic_const_exprs)]
+
+trait ConstName {
+    const NAME_BYTES: &'static [u8];
+}
+
+impl const ConstName for u8 {
+    const NAME_BYTES: &'static [u8] = b"u8";
+}
+
+const fn name_len<T: ?Sized + ConstName>() -> usize {
+    T::NAME_BYTES.len()
+}
+
+impl<T: ?Sized + ConstName> const ConstName for &T
+where
+    [(); name_len::<T>()]:,
+{
+    const NAME_BYTES: &'static [u8] = b"&T";
+}
+
+impl<T: ?Sized + ConstName> const ConstName for &mut T
+where
+    [(); name_len::<T>()]:,
+{
+    const NAME_BYTES: &'static [u8] = b"&mut T";
+}
+
+pub const ICE_1: &'static [u8] = <&&mut u8 as ConstName>::NAME_BYTES;
+pub const ICE_2: &'static [u8] = <&mut &u8 as ConstName>::NAME_BYTES;
+
+fn main() {}
diff --git a/src/test/ui/error-codes/E0604.stderr b/src/test/ui/error-codes/E0604.stderr
index d715d28b73c01..68da03928b783 100644
--- a/src/test/ui/error-codes/E0604.stderr
+++ b/src/test/ui/error-codes/E0604.stderr
@@ -1,14 +1,11 @@
 error[E0604]: only `u8` can be cast as `char`, not `u32`
   --> $DIR/E0604.rs:2:5
    |
-LL |     1u32 as char;
-   |     ^^^^^^^^^^^^ invalid cast
-   |
-help: try `char::from_u32` instead
-  --> $DIR/E0604.rs:2:5
-   |
 LL |     1u32 as char;
    |     ^^^^^^^^^^^^
+   |     |
+   |     invalid cast
+   |     help: try `char::from_u32` instead: `char::from_u32(1u32)`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-festival.stderr b/src/test/ui/error-festival.stderr
index 0ddb6fc99b004..81aa268cacc5c 100644
--- a/src/test/ui/error-festival.stderr
+++ b/src/test/ui/error-festival.stderr
@@ -56,14 +56,11 @@ LL | | }
 error[E0604]: only `u8` can be cast as `char`, not `u32`
   --> $DIR/error-festival.rs:25:5
    |
-LL |     0u32 as char;
-   |     ^^^^^^^^^^^^ invalid cast
-   |
-help: try `char::from_u32` instead
-  --> $DIR/error-festival.rs:25:5
-   |
 LL |     0u32 as char;
    |     ^^^^^^^^^^^^
+   |     |
+   |     invalid cast
+   |     help: try `char::from_u32` instead: `char::from_u32(0u32)`
 
 error[E0605]: non-primitive cast: `u8` as `Vec<u8>`
   --> $DIR/error-festival.rs:29:5
diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr
index 84220ea172a11..3a508459cc046 100644
--- a/src/test/ui/mismatched_types/cast-rfc0401.stderr
+++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr
@@ -97,14 +97,11 @@ LL |     let _ = E::A as bool;
 error[E0604]: only `u8` can be cast as `char`, not `u32`
   --> $DIR/cast-rfc0401.rs:41:13
    |
-LL |     let _ = 0x61u32 as char;
-   |             ^^^^^^^^^^^^^^^ invalid cast
-   |
-help: try `char::from_u32` instead
-  --> $DIR/cast-rfc0401.rs:41:13
-   |
 LL |     let _ = 0x61u32 as char;
    |             ^^^^^^^^^^^^^^^
+   |             |
+   |             invalid cast
+   |             help: try `char::from_u32` instead: `char::from_u32(0x61u32)`
 
 error[E0606]: casting `bool` as `f32` is invalid
   --> $DIR/cast-rfc0401.rs:43:13