about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-03-19 12:39:34 +0000
committerbors <bors@rust-lang.org>2025-03-19 12:39:34 +0000
commita7fc463dd8fbeca800d4b3efc501069502cffe64 (patch)
tree097c6944fd8660666094e1c1f7adfca493dd37dc /compiler
parentc4b38a596767c9c6275c937cf3a2d4b9612b4875 (diff)
parent3b7faca09c7a2e86390e354e83cb1acac6b3a1fd (diff)
Auto merge of #138693 - matthiaskrgr:rollup-ejq8mwp, r=matthiaskrgr
Rollup of 10 pull requests

Successful merges:

 - #136177 (clarify BufRead::{fill_buf, consume} docs)
 - #138654 (Remove the regex dependency from coretests)
 - #138655 (rustc-dev-guide sync)
 - #138656 (Remove double nesting in post-merge workflow)
 - #138658 (CI: mirror alpine and centos images to ghcr)
 - #138659 (coverage: Don't store a body span in `FunctionCoverageInfo`)
 - #138661 (Revert: Add *_value methods to proc_macro lib)
 - #138670 (Remove existing AFIDT implementation)
 - #138674 (Various codegen_llvm cleanups)
 - #138684 (use then in docs for `fuse` to enhance readability)

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast/Cargo.toml1
-rw-r--r--compiler/rustc_ast/src/util/literal.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs14
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs30
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs238
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs53
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs7
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs39
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs69
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs2
-rw-r--r--compiler/rustc_lexer/Cargo.toml1
-rw-r--r--compiler/rustc_lexer/src/lib.rs4
-rw-r--r--compiler/rustc_lexer/src/unescape.rs438
-rw-r--r--compiler/rustc_lexer/src/unescape/tests.rs286
-rw-r--r--compiler/rustc_middle/src/mir/coverage.rs1
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs3
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs5
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs1
-rw-r--r--compiler/rustc_middle/src/ty/return_position_impl_trait_in_trait.rs95
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs1
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs50
-rw-r--r--compiler/rustc_parse/Cargo.toml1
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs6
-rw-r--r--compiler/rustc_parse/src/lexer/unescape_error_reporting.rs2
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs2
-rw-r--r--compiler/rustc_parse_format/Cargo.toml1
-rw-r--r--compiler/rustc_parse_format/src/lib.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs28
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs58
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs6
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs25
32 files changed, 966 insertions, 519 deletions
diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml
index 7f0db1560c1..902287d0328 100644
--- a/compiler/rustc_ast/Cargo.toml
+++ b/compiler/rustc_ast/Cargo.toml
@@ -6,7 +6,6 @@ edition = "2024"
 [dependencies]
 # tidy-alphabetical-start
 bitflags = "2.4.1"
-literal-escaper = { path = "../../library/literal-escaper" }
 memchr = "2.7.4"
 rustc_ast_ir = { path = "../rustc_ast_ir" }
 rustc_data_structures = { path = "../rustc_data_structures" }
diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs
index 121331ece6d..6896ac723fa 100644
--- a/compiler/rustc_ast/src/util/literal.rs
+++ b/compiler/rustc_ast/src/util/literal.rs
@@ -2,7 +2,7 @@
 
 use std::{ascii, fmt, str};
 
-use literal_escaper::{
+use rustc_lexer::unescape::{
     MixedUnit, Mode, byte_from_char, unescape_byte, unescape_char, unescape_mixed, unescape_unicode,
 };
 use rustc_span::{Span, Symbol, kw, sym};
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
index 80e54bf045e..5b487bc1a8b 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
@@ -105,9 +105,14 @@ fn fill_region_tables<'tcx>(
     ids_info: &'tcx CoverageIdsInfo,
     covfun: &mut CovfunRecord<'tcx>,
 ) {
-    // Currently a function's mappings must all be in the same file as its body span.
+    // Currently a function's mappings must all be in the same file, so use the
+    // first mapping's span to determine the file.
     let source_map = tcx.sess.source_map();
-    let source_file = source_map.lookup_source_file(fn_cov_info.body_span.lo());
+    let Some(first_span) = (try { fn_cov_info.mappings.first()?.span }) else {
+        debug_assert!(false, "function has no mappings: {:?}", covfun.mangled_function_name);
+        return;
+    };
+    let source_file = source_map.lookup_source_file(first_span.lo());
 
     // Look up the global file ID for that file.
     let global_file_id = global_file_table.global_file_id_for_file(&source_file);
@@ -118,9 +123,8 @@ fn fill_region_tables<'tcx>(
     let ffi::Regions { code_regions, branch_regions, mcdc_branch_regions, mcdc_decision_regions } =
         &mut covfun.regions;
 
-    let make_cov_span = |span: Span| {
-        spans::make_coverage_span(local_file_id, source_map, fn_cov_info, &source_file, span)
-    };
+    let make_cov_span =
+        |span: Span| spans::make_coverage_span(local_file_id, source_map, &source_file, span);
     let discard_all = tcx.sess.coverage_discard_all_spans_in_codegen();
 
     // For each counter/region pair in this function+file, convert it to a
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs
index 6d1d91340c2..3193be31ada 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs
@@ -1,4 +1,3 @@
-use rustc_middle::mir::coverage::FunctionCoverageInfo;
 use rustc_span::source_map::SourceMap;
 use rustc_span::{BytePos, Pos, SourceFile, Span};
 use tracing::debug;
@@ -19,11 +18,10 @@ use crate::coverageinfo::mapgen::LocalFileId;
 pub(crate) fn make_coverage_span(
     file_id: LocalFileId,
     source_map: &SourceMap,
-    fn_cov_info: &FunctionCoverageInfo,
     file: &SourceFile,
     span: Span,
 ) -> Option<ffi::CoverageSpan> {
-    let span = ensure_non_empty_span(source_map, fn_cov_info, span)?;
+    let span = ensure_non_empty_span(source_map, span)?;
 
     let lo = span.lo();
     let hi = span.hi();
@@ -55,36 +53,22 @@ pub(crate) fn make_coverage_span(
     })
 }
 
-fn ensure_non_empty_span(
-    source_map: &SourceMap,
-    fn_cov_info: &FunctionCoverageInfo,
-    span: Span,
-) -> Option<Span> {
+fn ensure_non_empty_span(source_map: &SourceMap, span: Span) -> Option<Span> {
     if !span.is_empty() {
         return Some(span);
     }
 
-    let lo = span.lo();
-    let hi = span.hi();
-
-    // The span is empty, so try to expand it to cover an adjacent '{' or '}',
-    // but only within the bounds of the body span.
-    let try_next = hi < fn_cov_info.body_span.hi();
-    let try_prev = fn_cov_info.body_span.lo() < lo;
-    if !(try_next || try_prev) {
-        return None;
-    }
-
+    // The span is empty, so try to enlarge it to cover an adjacent '{' or '}'.
     source_map
         .span_to_source(span, |src, start, end| try {
             // Adjusting span endpoints by `BytePos(1)` is normally a bug,
             // but in this case we have specifically checked that the character
             // we're skipping over is one of two specific ASCII characters, so
             // adjusting by exactly 1 byte is correct.
-            if try_next && src.as_bytes()[end] == b'{' {
-                Some(span.with_hi(hi + BytePos(1)))
-            } else if try_prev && src.as_bytes()[start - 1] == b'}' {
-                Some(span.with_lo(lo - BytePos(1)))
+            if src.as_bytes().get(end).copied() == Some(b'{') {
+                Some(span.with_hi(span.hi() + BytePos(1)))
+            } else if start > 0 && src.as_bytes()[start - 1] == b'}' {
+                Some(span.with_lo(span.lo() - BytePos(1)))
             } else {
                 None
             }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 98d59f5a8ae..2eaaf127e41 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -2,6 +2,7 @@ use std::borrow::Cow;
 use std::fmt::{self, Write};
 use std::hash::{Hash, Hasher};
 use std::path::{Path, PathBuf};
+use std::sync::Arc;
 use std::{iter, ptr};
 
 use libc::{c_char, c_longlong, c_uint};
@@ -38,8 +39,8 @@ use crate::debuginfo::metadata::type_map::build_type_with_children;
 use crate::debuginfo::utils::{WidePtrKind, wide_pointer_kind};
 use crate::llvm;
 use crate::llvm::debuginfo::{
-    DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType, DebugEmissionKind,
-    DebugNameTableKind,
+    DIBasicType, DIBuilder, DICompositeType, DIDescriptor, DIFile, DIFlags, DILexicalBlock,
+    DIScope, DIType, DebugEmissionKind, DebugNameTableKind,
 };
 use crate::value::Value;
 
@@ -68,7 +69,8 @@ pub(super) const UNKNOWN_COLUMN_NUMBER: c_uint = 0;
 
 const NO_SCOPE_METADATA: Option<&DIScope> = None;
 /// A function that returns an empty list of generic parameter debuginfo nodes.
-const NO_GENERICS: for<'ll> fn(&CodegenCx<'ll, '_>) -> SmallVec<&'ll DIType> = |_| SmallVec::new();
+const NO_GENERICS: for<'ll> fn(&CodegenCx<'ll, '_>) -> SmallVec<Option<&'ll DIType>> =
+    |_| SmallVec::new();
 
 // SmallVec is used quite a bit in this module, so create a shorthand.
 // The actual number of elements is not so important.
@@ -243,7 +245,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
                             cx,
                             owner,
                             addr_field_name,
-                            (addr_field.size, addr_field.align.abi),
+                            addr_field,
                             layout.fields.offset(WIDE_PTR_ADDR),
                             DIFlags::FlagZero,
                             data_ptr_type_di_node,
@@ -253,7 +255,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
                             cx,
                             owner,
                             extra_field_name,
-                            (extra_field.size, extra_field.align.abi),
+                            extra_field,
                             layout.fields.offset(WIDE_PTR_EXTRA),
                             DIFlags::FlagZero,
                             type_di_node(cx, extra_field.ty),
@@ -311,12 +313,7 @@ fn build_subroutine_type_di_node<'ll, 'tcx>(
 
     debug_context(cx).type_map.unique_id_to_di_node.borrow_mut().remove(&unique_type_id);
 
-    let fn_di_node = unsafe {
-        llvm::LLVMRustDIBuilderCreateSubroutineType(
-            DIB(cx),
-            create_DIArray(DIB(cx), &signature_di_nodes[..]),
-        )
-    };
+    let fn_di_node = create_subroutine_type(cx, create_DIArray(DIB(cx), &signature_di_nodes[..]));
 
     // This is actually a function pointer, so wrap it in pointer DI.
     let name = compute_debuginfo_type_name(cx.tcx, fn_ty, false);
@@ -340,6 +337,13 @@ fn build_subroutine_type_di_node<'ll, 'tcx>(
     DINodeCreationResult::new(di_node, false)
 }
 
+pub(super) fn create_subroutine_type<'ll>(
+    cx: &CodegenCx<'ll, '_>,
+    signature: &'ll DICompositeType,
+) -> &'ll DICompositeType {
+    unsafe { llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(cx), signature) }
+}
+
 /// Create debuginfo for `dyn SomeTrait` types. Currently these are empty structs
 /// we with the correct type name (e.g. "dyn SomeTrait<Foo, Item=u32> + Sync").
 fn build_dyn_type_di_node<'ll, 'tcx>(
@@ -487,26 +491,22 @@ pub(crate) fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) ->
 // FIXME(mw): Cache this via a regular UniqueTypeId instead of an extra field in the debug context.
 fn recursion_marker_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> &'ll DIType {
     *debug_context(cx).recursion_marker_type.get_or_init(move || {
-        unsafe {
-            // The choice of type here is pretty arbitrary -
-            // anything reading the debuginfo for a recursive
-            // type is going to see *something* weird - the only
-            // question is what exactly it will see.
-            //
-            // FIXME: the name `<recur_type>` does not fit the naming scheme
-            //        of other types.
-            //
-            // FIXME: it might make sense to use an actual pointer type here
-            //        so that debuggers can show the address.
-            let name = "<recur_type>";
-            llvm::LLVMRustDIBuilderCreateBasicType(
-                DIB(cx),
-                name.as_c_char_ptr(),
-                name.len(),
-                cx.tcx.data_layout.pointer_size.bits(),
-                dwarf_const::DW_ATE_unsigned,
-            )
-        }
+        // The choice of type here is pretty arbitrary -
+        // anything reading the debuginfo for a recursive
+        // type is going to see *something* weird - the only
+        // question is what exactly it will see.
+        //
+        // FIXME: the name `<recur_type>` does not fit the naming scheme
+        //        of other types.
+        //
+        // FIXME: it might make sense to use an actual pointer type here
+        //        so that debuggers can show the address.
+        create_basic_type(
+            cx,
+            "<recur_type>",
+            cx.tcx.data_layout.pointer_size,
+            dwarf_const::DW_ATE_unsigned,
+        )
     })
 }
 
@@ -620,42 +620,38 @@ pub(crate) fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFi
         let source =
             cx.sess().opts.unstable_opts.embed_source.then_some(()).and(source_file.src.as_ref());
 
-        unsafe {
-            llvm::LLVMRustDIBuilderCreateFile(
-                DIB(cx),
-                file_name.as_c_char_ptr(),
-                file_name.len(),
-                directory.as_c_char_ptr(),
-                directory.len(),
-                hash_kind,
-                hash_value.as_c_char_ptr(),
-                hash_value.len(),
-                source.map_or(ptr::null(), |x| x.as_c_char_ptr()),
-                source.map_or(0, |x| x.len()),
-            )
-        }
+        create_file(DIB(cx), &file_name, &directory, &hash_value, hash_kind, source)
     }
 }
 
 fn unknown_file_metadata<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile {
-    debug_context(cx).created_files.borrow_mut().entry(None).or_insert_with(|| unsafe {
-        let file_name = "<unknown>";
-        let directory = "";
-        let hash_value = "";
+    debug_context(cx).created_files.borrow_mut().entry(None).or_insert_with(|| {
+        create_file(DIB(cx), "<unknown>", "", "", llvm::ChecksumKind::None, None)
+    })
+}
 
+fn create_file<'ll>(
+    builder: &DIBuilder<'ll>,
+    file_name: &str,
+    directory: &str,
+    hash_value: &str,
+    hash_kind: llvm::ChecksumKind,
+    source: Option<&Arc<String>>,
+) -> &'ll DIFile {
+    unsafe {
         llvm::LLVMRustDIBuilderCreateFile(
-            DIB(cx),
+            builder,
             file_name.as_c_char_ptr(),
             file_name.len(),
             directory.as_c_char_ptr(),
             directory.len(),
-            llvm::ChecksumKind::None,
+            hash_kind,
             hash_value.as_c_char_ptr(),
             hash_value.len(),
-            ptr::null(),
-            0,
+            source.map_or(ptr::null(), |x| x.as_c_char_ptr()),
+            source.map_or(0, |x| x.len()),
         )
-    })
+    }
 }
 
 trait MsvcBasicName {
@@ -742,7 +738,7 @@ fn build_cpp_f16_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> DINodeCreation
                 cx,
                 float_di_node,
                 "bits",
-                cx.size_and_align_of(bits_ty),
+                cx.layout_of(bits_ty),
                 Size::ZERO,
                 DIFlags::FlagZero,
                 type_di_node(cx, bits_ty),
@@ -788,15 +784,7 @@ fn build_basic_type_di_node<'ll, 'tcx>(
         _ => bug!("debuginfo::build_basic_type_di_node - `t` is invalid type"),
     };
 
-    let ty_di_node = unsafe {
-        llvm::LLVMRustDIBuilderCreateBasicType(
-            DIB(cx),
-            name.as_c_char_ptr(),
-            name.len(),
-            cx.size_of(t).bits(),
-            encoding,
-        )
-    };
+    let ty_di_node = create_basic_type(cx, name, cx.size_of(t), encoding);
 
     if !cpp_like_debuginfo {
         return DINodeCreationResult::new(ty_di_node, false);
@@ -824,6 +812,23 @@ fn build_basic_type_di_node<'ll, 'tcx>(
     DINodeCreationResult::new(typedef_di_node, false)
 }
 
+fn create_basic_type<'ll, 'tcx>(
+    cx: &CodegenCx<'ll, 'tcx>,
+    name: &str,
+    size: Size,
+    encoding: u32,
+) -> &'ll DIBasicType {
+    unsafe {
+        llvm::LLVMRustDIBuilderCreateBasicType(
+            DIB(cx),
+            name.as_c_char_ptr(),
+            name.len(),
+            size.bits(),
+            encoding,
+        )
+    }
+}
+
 fn build_foreign_type_di_node<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     t: Ty<'tcx>,
@@ -929,17 +934,13 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>(
     };
 
     unsafe {
-        let compile_unit_file = llvm::LLVMRustDIBuilderCreateFile(
+        let compile_unit_file = create_file(
             debug_context.builder.as_ref(),
-            name_in_debuginfo.as_c_char_ptr(),
-            name_in_debuginfo.len(),
-            work_dir.as_c_char_ptr(),
-            work_dir.len(),
+            &name_in_debuginfo,
+            &work_dir,
+            "",
             llvm::ChecksumKind::None,
-            ptr::null(),
-            0,
-            ptr::null(),
-            0,
+            None,
         );
 
         let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit(
@@ -971,7 +972,7 @@ fn build_field_di_node<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     owner: &'ll DIScope,
     name: &str,
-    size_and_align: (Size, Align),
+    layout: TyAndLayout<'tcx>,
     offset: Size,
     flags: DIFlags,
     type_di_node: &'ll DIType,
@@ -983,6 +984,30 @@ fn build_field_di_node<'ll, 'tcx>(
     } else {
         (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)
     };
+    create_member_type(
+        cx,
+        owner,
+        name,
+        file_metadata,
+        line_number,
+        layout,
+        offset,
+        flags,
+        type_di_node,
+    )
+}
+
+fn create_member_type<'ll, 'tcx>(
+    cx: &CodegenCx<'ll, 'tcx>,
+    owner: &'ll DIScope,
+    name: &str,
+    file_metadata: &'ll DIType,
+    line_number: u32,
+    layout: TyAndLayout<'tcx>,
+    offset: Size,
+    flags: DIFlags,
+    type_di_node: &'ll DIType,
+) -> &'ll DIType {
     unsafe {
         llvm::LLVMRustDIBuilderCreateMemberType(
             DIB(cx),
@@ -991,8 +1016,8 @@ fn build_field_di_node<'ll, 'tcx>(
             name.len(),
             file_metadata,
             line_number,
-            size_and_align.0.bits(),
-            size_and_align.1.bits() as u32,
+            layout.size.bits(),
+            layout.align.abi.bits() as u32,
             offset.bits(),
             flags,
             type_di_node,
@@ -1076,7 +1101,7 @@ fn build_struct_type_di_node<'ll, 'tcx>(
                         cx,
                         owner,
                         &field_name[..],
-                        (field_layout.size, field_layout.align.abi),
+                        field_layout,
                         struct_type_and_layout.fields.offset(i),
                         visibility_di_flags(cx, f.did, adt_def.did()),
                         type_di_node(cx, field_layout.ty),
@@ -1126,7 +1151,7 @@ fn build_upvar_field_di_nodes<'ll, 'tcx>(
                 cx,
                 closure_or_coroutine_di_node,
                 capture_name.as_str(),
-                cx.size_and_align_of(up_var_ty),
+                cx.layout_of(up_var_ty),
                 layout.fields.offset(index),
                 DIFlags::FlagZero,
                 type_di_node(cx, up_var_ty),
@@ -1171,7 +1196,7 @@ fn build_tuple_type_di_node<'ll, 'tcx>(
                         cx,
                         tuple_di_node,
                         &tuple_field_name(index),
-                        cx.size_and_align_of(component_type),
+                        cx.layout_of(component_type),
                         tuple_type_and_layout.fields.offset(index),
                         DIFlags::FlagZero,
                         type_di_node(cx, component_type),
@@ -1269,7 +1294,7 @@ fn build_union_type_di_node<'ll, 'tcx>(
                         cx,
                         owner,
                         f.name.as_str(),
-                        size_and_align_of(field_layout),
+                        field_layout,
                         Size::ZERO,
                         DIFlags::FlagZero,
                         type_di_node(cx, field_layout.ty),
@@ -1287,32 +1312,33 @@ fn build_union_type_di_node<'ll, 'tcx>(
 fn build_generic_type_param_di_nodes<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     ty: Ty<'tcx>,
-) -> SmallVec<&'ll DIType> {
+) -> SmallVec<Option<&'ll DIType>> {
     if let ty::Adt(def, args) = *ty.kind() {
-        if args.types().next().is_some() {
-            let generics = cx.tcx.generics_of(def.did());
-            let names = get_parameter_names(cx, generics);
-            let template_params: SmallVec<_> = iter::zip(args, names)
-                .filter_map(|(kind, name)| {
-                    kind.as_type().map(|ty| {
-                        let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
-                        let actual_type_di_node = type_di_node(cx, actual_type);
-                        let name = name.as_str();
-                        unsafe {
-                            llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
-                                DIB(cx),
-                                None,
-                                name.as_c_char_ptr(),
-                                name.len(),
-                                actual_type_di_node,
-                            )
-                        }
-                    })
+        let generics = cx.tcx.generics_of(def.did());
+        return get_template_parameters(cx, generics, args);
+    }
+
+    return smallvec![];
+}
+
+pub(super) fn get_template_parameters<'ll, 'tcx>(
+    cx: &CodegenCx<'ll, 'tcx>,
+    generics: &ty::Generics,
+    args: ty::GenericArgsRef<'tcx>,
+) -> SmallVec<Option<&'ll DIType>> {
+    if args.types().next().is_some() {
+        let names = get_parameter_names(cx, generics);
+        let template_params: SmallVec<_> = iter::zip(args, names)
+            .filter_map(|(kind, name)| {
+                kind.as_type().map(|ty| {
+                    let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
+                    let actual_type_di_node = type_di_node(cx, actual_type);
+                    Some(cx.create_template_type_parameter(name.as_str(), actual_type_di_node))
                 })
-                .collect();
+            })
+            .collect();
 
-            return template_params;
-        }
+        return template_params;
     }
 
     return smallvec![];
@@ -1416,7 +1442,9 @@ fn build_vtable_type_di_node<'ll, 'tcx>(
     let void_pointer_ty = Ty::new_imm_ptr(tcx, tcx.types.unit);
     let void_pointer_type_di_node = type_di_node(cx, void_pointer_ty);
     let usize_di_node = type_di_node(cx, tcx.types.usize);
-    let (pointer_size, pointer_align) = cx.size_and_align_of(void_pointer_ty);
+    let pointer_layout = cx.layout_of(void_pointer_ty);
+    let pointer_size = pointer_layout.size;
+    let pointer_align = pointer_layout.align.abi;
     // If `usize` is not pointer-sized and -aligned then the size and alignment computations
     // for the vtable as a whole would be wrong. Let's make sure this holds even on weird
     // platforms.
@@ -1472,7 +1500,7 @@ fn build_vtable_type_di_node<'ll, 'tcx>(
                         cx,
                         vtable_type_di_node,
                         &field_name,
-                        (pointer_size, pointer_align),
+                        pointer_layout,
                         field_offset,
                         DIFlags::FlagZero,
                         field_type_di_node,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
index a72e205c9b2..07075be55fa 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
@@ -17,8 +17,8 @@ use crate::debuginfo::metadata::enums::DiscrResult;
 use crate::debuginfo::metadata::type_map::{self, Stub, UniqueTypeId};
 use crate::debuginfo::metadata::{
     DINodeCreationResult, NO_GENERICS, NO_SCOPE_METADATA, SmallVec, UNKNOWN_LINE_NUMBER,
-    build_field_di_node, file_metadata, file_metadata_from_def_id, size_and_align_of, type_di_node,
-    unknown_file_metadata, visibility_di_flags,
+    build_field_di_node, create_member_type, file_metadata, file_metadata_from_def_id,
+    size_and_align_of, type_di_node, unknown_file_metadata, visibility_di_flags,
 };
 use crate::debuginfo::utils::DIB;
 use crate::llvm::debuginfo::{DIFile, DIFlags, DIType};
@@ -370,9 +370,9 @@ fn build_single_variant_union_fields<'ll, 'tcx>(
             cx,
             enum_type_di_node,
             &variant_union_field_name(variant_index),
-            // NOTE: We use the size and align of the entire type, not from variant_layout
+            // NOTE: We use the layout of the entire type, not from variant_layout
             //       since the later is sometimes smaller (if it has fewer fields).
-            size_and_align_of(enum_type_and_layout),
+            enum_type_and_layout,
             Size::ZERO,
             visibility_flags,
             variant_struct_type_wrapper_di_node,
@@ -560,7 +560,7 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>(
                 cx,
                 wrapper_struct_type_di_node,
                 "value",
-                size_and_align_of(enum_or_coroutine_type_and_layout),
+                enum_or_coroutine_type_and_layout,
                 Size::ZERO,
                 DIFlags::FlagZero,
                 variant_struct_type_di_node,
@@ -820,7 +820,6 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>(
             .unwrap_or_else(|| (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER));
 
         let field_name = variant_union_field_name(variant_member_info.variant_index);
-        let (size, align) = size_and_align_of(enum_type_and_layout);
 
         let variant_struct_type_wrapper = build_variant_struct_wrapper_type_di_node(
             cx,
@@ -840,27 +839,23 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>(
             },
         );
 
-        // We use LLVMRustDIBuilderCreateMemberType() member type directly because
+        // We use create_member_type() member type directly because
         // the build_field_di_node() function does not support specifying a source location,
         // which is something that we don't do anywhere else.
-        unsafe {
-            llvm::LLVMRustDIBuilderCreateMemberType(
-                DIB(cx),
-                enum_type_di_node,
-                field_name.as_c_char_ptr(),
-                field_name.len(),
-                file_di_node,
-                line_number,
-                // NOTE: We use the size and align of the entire type, not from variant_layout
-                //       since the later is sometimes smaller (if it has fewer fields).
-                size.bits(),
-                align.bits() as u32,
-                // Union fields are always at offset zero
-                Size::ZERO.bits(),
-                di_flags,
-                variant_struct_type_wrapper,
-            )
-        }
+        create_member_type(
+            cx,
+            enum_type_di_node,
+            &field_name,
+            file_di_node,
+            line_number,
+            // NOTE: We use the layout of the entire type, not from variant_layout
+            //       since the later is sometimes smaller (if it has fewer fields).
+            enum_type_and_layout,
+            // Union fields are always at offset zero
+            Size::ZERO,
+            di_flags,
+            variant_struct_type_wrapper,
+        )
     }));
 
     assert_eq!(
@@ -874,7 +869,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>(
 
     if is_128_bits {
         let type_di_node = type_di_node(cx, cx.tcx.types.u64);
-        let size_and_align = cx.size_and_align_of(cx.tcx.types.u64);
+        let u64_layout = cx.layout_of(cx.tcx.types.u64);
 
         let (lo_offset, hi_offset) = match cx.tcx.data_layout.endian {
             Endian::Little => (0, 8),
@@ -889,7 +884,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>(
             cx,
             enum_type_di_node,
             TAG_FIELD_NAME_128_LO,
-            size_and_align,
+            u64_layout,
             lo_offset,
             di_flags,
             type_di_node,
@@ -900,7 +895,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>(
             cx,
             enum_type_di_node,
             TAG_FIELD_NAME_128_HI,
-            size_and_align,
+            u64_layout,
             hi_offset,
             DIFlags::FlagZero,
             type_di_node,
@@ -911,7 +906,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>(
             cx,
             enum_type_di_node,
             TAG_FIELD_NAME,
-            cx.size_and_align_of(enum_type_and_layout.field(cx, tag_field).ty),
+            enum_type_and_layout.field(cx, tag_field),
             enum_type_and_layout.fields.offset(tag_field),
             di_flags,
             tag_base_type_di_node,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
index 9f6a5cc89e0..6792c307fdc 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
@@ -249,7 +249,7 @@ fn build_enum_variant_struct_type_di_node<'ll, 'tcx>(
                         cx,
                         struct_type_di_node,
                         &field_name,
-                        (field_layout.size, field_layout.align.abi),
+                        field_layout,
                         variant_layout.fields.offset(field_index),
                         di_flags,
                         type_di_node(cx, field_layout.ty),
@@ -332,7 +332,7 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(
                         cx,
                         variant_struct_type_di_node,
                         &field_name,
-                        cx.size_and_align_of(field_type),
+                        cx.layout_of(field_type),
                         variant_layout.fields.offset(field_index),
                         DIFlags::FlagZero,
                         type_di_node(cx, field_type),
@@ -352,7 +352,7 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(
                         cx,
                         variant_struct_type_di_node,
                         upvar_name.as_str(),
-                        cx.size_and_align_of(upvar_ty),
+                        cx.layout_of(upvar_ty),
                         coroutine_type_and_layout.fields.offset(index),
                         DIFlags::FlagZero,
                         type_di_node(cx, upvar_ty),
@@ -363,6 +363,7 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(
 
             state_specific_fields.into_iter().chain(common_fields).collect()
         },
+        // FIXME: this is a no-op. `build_generic_type_param_di_nodes` only works for Adts.
         |cx| build_generic_type_param_di_nodes(cx, coroutine_type_and_layout.ty),
     )
     .di_node
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
index 187d97c54c8..bfd131cfd3d 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
@@ -13,9 +13,9 @@ use smallvec::smallvec;
 use crate::common::{AsCCharPtr, CodegenCx};
 use crate::debuginfo::metadata::type_map::{self, Stub, StubInfo, UniqueTypeId};
 use crate::debuginfo::metadata::{
-    DINodeCreationResult, NO_GENERICS, SmallVec, UNKNOWN_LINE_NUMBER, file_metadata,
-    file_metadata_from_def_id, size_and_align_of, type_di_node, unknown_file_metadata,
-    visibility_di_flags,
+    DINodeCreationResult, NO_GENERICS, SmallVec, UNKNOWN_LINE_NUMBER, create_member_type,
+    file_metadata, file_metadata_from_def_id, size_and_align_of, type_di_node,
+    unknown_file_metadata, visibility_di_flags,
 };
 use crate::debuginfo::utils::{DIB, create_DIArray, get_namespace_for_item};
 use crate::llvm::debuginfo::{DIFile, DIFlags, DIType};
@@ -363,23 +363,22 @@ fn build_discr_member_di_node<'ll, 'tcx>(
 
         &Variants::Multiple { tag_field, .. } => {
             let tag_base_type = tag_base_type(cx.tcx, enum_or_coroutine_type_and_layout);
-            let (size, align) = cx.size_and_align_of(tag_base_type);
-
-            unsafe {
-                Some(llvm::LLVMRustDIBuilderCreateMemberType(
-                    DIB(cx),
-                    containing_scope,
-                    tag_name.as_c_char_ptr(),
-                    tag_name.len(),
-                    unknown_file_metadata(cx),
-                    UNKNOWN_LINE_NUMBER,
-                    size.bits(),
-                    align.bits() as u32,
-                    enum_or_coroutine_type_and_layout.fields.offset(tag_field).bits(),
-                    DIFlags::FlagArtificial,
-                    type_di_node(cx, tag_base_type),
-                ))
-            }
+            let ty = type_di_node(cx, tag_base_type);
+            let file = unknown_file_metadata(cx);
+
+            let layout = cx.layout_of(tag_base_type);
+
+            Some(create_member_type(
+                cx,
+                containing_scope,
+                &tag_name,
+                file,
+                UNKNOWN_LINE_NUMBER,
+                layout,
+                enum_or_coroutine_type_and_layout.fields.offset(tag_field),
+                DIFlags::FlagArtificial,
+                ty,
+            ))
         }
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
index af1d503ad6a..ae2ab32ef53 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
@@ -257,7 +257,7 @@ pub(super) fn build_type_with_children<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     stub_info: StubInfo<'ll, 'tcx>,
     members: impl FnOnce(&CodegenCx<'ll, 'tcx>, &'ll DIType) -> SmallVec<&'ll DIType>,
-    generics: impl FnOnce(&CodegenCx<'ll, 'tcx>) -> SmallVec<&'ll DIType>,
+    generics: impl FnOnce(&CodegenCx<'ll, 'tcx>) -> SmallVec<Option<&'ll DIType>>,
 ) -> DINodeCreationResult<'ll> {
     assert_eq!(debug_context(cx).type_map.di_node_for_unique_id(stub_info.unique_type_id), None);
 
@@ -265,8 +265,7 @@ pub(super) fn build_type_with_children<'ll, 'tcx>(
 
     let members: SmallVec<_> =
         members(cx, stub_info.metadata).into_iter().map(|node| Some(node)).collect();
-    let generics: SmallVec<Option<&'ll DIType>> =
-        generics(cx).into_iter().map(|node| Some(node)).collect();
+    let generics = generics(cx);
 
     if !(members.is_empty() && generics.is_empty()) {
         unsafe {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 10819a53b1d..ae7d080db66 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -2,10 +2,11 @@
 
 use std::cell::{OnceCell, RefCell};
 use std::ops::Range;
+use std::ptr;
 use std::sync::Arc;
-use std::{iter, ptr};
 
 use libc::c_uint;
+use metadata::create_subroutine_type;
 use rustc_abi::Size;
 use rustc_codegen_ssa::debuginfo::type_names;
 use rustc_codegen_ssa::mir::debuginfo::VariableKind::*;
@@ -34,8 +35,8 @@ use crate::builder::Builder;
 use crate::common::{AsCCharPtr, CodegenCx};
 use crate::llvm;
 use crate::llvm::debuginfo::{
-    DIArray, DIBuilderBox, DIFile, DIFlags, DILexicalBlock, DILocation, DISPFlags, DIScope, DIType,
-    DIVariable,
+    DIArray, DIBuilderBox, DIFile, DIFlags, DILexicalBlock, DILocation, DISPFlags, DIScope,
+    DITemplateTypeParameter, DIType, DIVariable,
 };
 use crate::value::Value;
 
@@ -251,7 +252,7 @@ struct DebugLoc {
     col: u32,
 }
 
-impl CodegenCx<'_, '_> {
+impl<'ll> CodegenCx<'ll, '_> {
     /// Looks up debug source information about a `BytePos`.
     // FIXME(eddyb) rename this to better indicate it's a duplicate of
     // `lookup_char_pos` rather than `dbg_loc`, perhaps by making
@@ -279,6 +280,22 @@ impl CodegenCx<'_, '_> {
             DebugLoc { file, line, col }
         }
     }
+
+    fn create_template_type_parameter(
+        &self,
+        name: &str,
+        actual_type_metadata: &'ll DIType,
+    ) -> &'ll DITemplateTypeParameter {
+        unsafe {
+            llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
+                DIB(self),
+                None,
+                name.as_c_char_ptr(),
+                name.len(),
+                actual_type_metadata,
+            )
+        }
+    }
 }
 
 impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
@@ -325,10 +342,8 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         let loc = self.lookup_debug_loc(span.lo());
         let file_metadata = file_metadata(self, &loc.file);
 
-        let function_type_metadata = unsafe {
-            let fn_signature = get_function_signature(self, fn_abi);
-            llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(self), fn_signature)
-        };
+        let function_type_metadata =
+            create_subroutine_type(self, get_function_signature(self, fn_abi));
 
         let mut name = String::with_capacity(64);
         type_names::push_item_name(tcx, def_id, false, &mut name);
@@ -471,46 +486,10 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
             generics: &ty::Generics,
             args: GenericArgsRef<'tcx>,
         ) -> &'ll DIArray {
-            if args.types().next().is_none() {
-                return create_DIArray(DIB(cx), &[]);
-            }
-
-            // Again, only create type information if full debuginfo is enabled
-            let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full {
-                let names = get_parameter_names(cx, generics);
-                iter::zip(args, names)
-                    .filter_map(|(kind, name)| {
-                        kind.as_type().map(|ty| {
-                            let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
-                            let actual_type_metadata = type_di_node(cx, actual_type);
-                            let name = name.as_str();
-                            unsafe {
-                                Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
-                                    DIB(cx),
-                                    None,
-                                    name.as_c_char_ptr(),
-                                    name.len(),
-                                    actual_type_metadata,
-                                ))
-                            }
-                        })
-                    })
-                    .collect()
-            } else {
-                vec![]
-            };
-
+            let template_params = metadata::get_template_parameters(cx, generics, args);
             create_DIArray(DIB(cx), &template_params)
         }
 
-        fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
-            let mut names = generics.parent.map_or_else(Vec::new, |def_id| {
-                get_parameter_names(cx, cx.tcx.generics_of(def_id))
-            });
-            names.extend(generics.own_params.iter().map(|param| param.name));
-            names
-        }
-
         /// Returns a scope, plus `true` if that's a type scope for "class" methods,
         /// otherwise `false` for plain namespace scopes.
         fn get_containing_scope<'ll, 'tcx>(
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index 7e1f35627e3..27643e715e6 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -176,7 +176,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                                 .in_definition_order()
                                 // We only care about associated types.
                                 .filter(|item| item.kind == ty::AssocKind::Type)
-                                // No RPITITs -- even with `async_fn_in_dyn_trait`, they are implicit.
+                                // No RPITITs -- they're not dyn-compatible for now.
                                 .filter(|item| !item.is_impl_trait_in_trait())
                                 // If the associated type has a `where Self: Sized` bound,
                                 // we do not need to constrain the associated type.
diff --git a/compiler/rustc_lexer/Cargo.toml b/compiler/rustc_lexer/Cargo.toml
index c72425fd92d..448a50faf45 100644
--- a/compiler/rustc_lexer/Cargo.toml
+++ b/compiler/rustc_lexer/Cargo.toml
@@ -16,7 +16,6 @@ Rust lexer used by rustc. No stability guarantees are provided.
 [dependencies]
 memchr = "2.7.4"
 unicode-xid = "0.2.0"
-literal-escaper = { path = "../../library/literal-escaper" }
 
 [dependencies.unicode-properties]
 version = "0.1.0"
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index c45dd33982b..61638e45253 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -26,13 +26,11 @@
 // tidy-alphabetical-end
 
 mod cursor;
+pub mod unescape;
 
 #[cfg(test)]
 mod tests;
 
-// FIXME: This is needed for rust-analyzer. Remove this dependency once rust-analyzer uses
-// `literal-escaper`.
-pub use literal_escaper as unescape;
 use unicode_properties::UnicodeEmoji;
 pub use unicode_xid::UNICODE_VERSION as UNICODE_XID_VERSION;
 
diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs
new file mode 100644
index 00000000000..d6ea4249247
--- /dev/null
+++ b/compiler/rustc_lexer/src/unescape.rs
@@ -0,0 +1,438 @@
+//! Utilities for validating string and char literals and turning them into
+//! values they represent.
+
+use std::ops::Range;
+use std::str::Chars;
+
+use Mode::*;
+
+#[cfg(test)]
+mod tests;
+
+/// Errors and warnings that can occur during string unescaping. They mostly
+/// relate to malformed escape sequences, but there are a few that are about
+/// other problems.
+#[derive(Debug, PartialEq, Eq)]
+pub enum EscapeError {
+    /// Expected 1 char, but 0 were found.
+    ZeroChars,
+    /// Expected 1 char, but more than 1 were found.
+    MoreThanOneChar,
+
+    /// Escaped '\' character without continuation.
+    LoneSlash,
+    /// Invalid escape character (e.g. '\z').
+    InvalidEscape,
+    /// Raw '\r' encountered.
+    BareCarriageReturn,
+    /// Raw '\r' encountered in raw string.
+    BareCarriageReturnInRawString,
+    /// Unescaped character that was expected to be escaped (e.g. raw '\t').
+    EscapeOnlyChar,
+
+    /// Numeric character escape is too short (e.g. '\x1').
+    TooShortHexEscape,
+    /// Invalid character in numeric escape (e.g. '\xz')
+    InvalidCharInHexEscape,
+    /// Character code in numeric escape is non-ascii (e.g. '\xFF').
+    OutOfRangeHexEscape,
+
+    /// '\u' not followed by '{'.
+    NoBraceInUnicodeEscape,
+    /// Non-hexadecimal value in '\u{..}'.
+    InvalidCharInUnicodeEscape,
+    /// '\u{}'
+    EmptyUnicodeEscape,
+    /// No closing brace in '\u{..}', e.g. '\u{12'.
+    UnclosedUnicodeEscape,
+    /// '\u{_12}'
+    LeadingUnderscoreUnicodeEscape,
+    /// More than 6 characters in '\u{..}', e.g. '\u{10FFFF_FF}'
+    OverlongUnicodeEscape,
+    /// Invalid in-bound unicode character code, e.g. '\u{DFFF}'.
+    LoneSurrogateUnicodeEscape,
+    /// Out of bounds unicode character code, e.g. '\u{FFFFFF}'.
+    OutOfRangeUnicodeEscape,
+
+    /// Unicode escape code in byte literal.
+    UnicodeEscapeInByte,
+    /// Non-ascii character in byte literal, byte string literal, or raw byte string literal.
+    NonAsciiCharInByte,
+
+    // `\0` in a C string literal.
+    NulInCStr,
+
+    /// After a line ending with '\', the next line contains whitespace
+    /// characters that are not skipped.
+    UnskippedWhitespaceWarning,
+
+    /// After a line ending with '\', multiple lines are skipped.
+    MultipleSkippedLinesWarning,
+}
+
+impl EscapeError {
+    /// Returns true for actual errors, as opposed to warnings.
+    pub fn is_fatal(&self) -> bool {
+        !matches!(
+            self,
+            EscapeError::UnskippedWhitespaceWarning | EscapeError::MultipleSkippedLinesWarning
+        )
+    }
+}
+
+/// Takes the contents of a unicode-only (non-mixed-utf8) literal (without
+/// quotes) and produces a sequence of escaped characters or errors.
+///
+/// Values are returned by invoking `callback`. For `Char` and `Byte` modes,
+/// the callback will be called exactly once.
+pub fn unescape_unicode<F>(src: &str, mode: Mode, callback: &mut F)
+where
+    F: FnMut(Range<usize>, Result<char, EscapeError>),
+{
+    match mode {
+        Char | Byte => {
+            let mut chars = src.chars();
+            let res = unescape_char_or_byte(&mut chars, mode);
+            callback(0..(src.len() - chars.as_str().len()), res);
+        }
+        Str | ByteStr => unescape_non_raw_common(src, mode, callback),
+        RawStr | RawByteStr => check_raw_common(src, mode, callback),
+        RawCStr => check_raw_common(src, mode, &mut |r, mut result| {
+            if let Ok('\0') = result {
+                result = Err(EscapeError::NulInCStr);
+            }
+            callback(r, result)
+        }),
+        CStr => unreachable!(),
+    }
+}
+
+/// Used for mixed utf8 string literals, i.e. those that allow both unicode
+/// chars and high bytes.
+pub enum MixedUnit {
+    /// Used for ASCII chars (written directly or via `\x00`..`\x7f` escapes)
+    /// and Unicode chars (written directly or via `\u` escapes).
+    ///
+    /// For example, if '¥' appears in a string it is represented here as
+    /// `MixedUnit::Char('¥')`, and it will be appended to the relevant byte
+    /// string as the two-byte UTF-8 sequence `[0xc2, 0xa5]`
+    Char(char),
+
+    /// Used for high bytes (`\x80`..`\xff`).
+    ///
+    /// For example, if `\xa5` appears in a string it is represented here as
+    /// `MixedUnit::HighByte(0xa5)`, and it will be appended to the relevant
+    /// byte string as the single byte `0xa5`.
+    HighByte(u8),
+}
+
+impl From<char> for MixedUnit {
+    fn from(c: char) -> Self {
+        MixedUnit::Char(c)
+    }
+}
+
+impl From<u8> for MixedUnit {
+    fn from(n: u8) -> Self {
+        if n.is_ascii() { MixedUnit::Char(n as char) } else { MixedUnit::HighByte(n) }
+    }
+}
+
+/// Takes the contents of a mixed-utf8 literal (without quotes) and produces
+/// a sequence of escaped characters or errors.
+///
+/// Values are returned by invoking `callback`.
+pub fn unescape_mixed<F>(src: &str, mode: Mode, callback: &mut F)
+where
+    F: FnMut(Range<usize>, Result<MixedUnit, EscapeError>),
+{
+    match mode {
+        CStr => unescape_non_raw_common(src, mode, &mut |r, mut result| {
+            if let Ok(MixedUnit::Char('\0')) = result {
+                result = Err(EscapeError::NulInCStr);
+            }
+            callback(r, result)
+        }),
+        Char | Byte | Str | RawStr | ByteStr | RawByteStr | RawCStr => unreachable!(),
+    }
+}
+
+/// Takes a contents of a char literal (without quotes), and returns an
+/// unescaped char or an error.
+pub fn unescape_char(src: &str) -> Result<char, EscapeError> {
+    unescape_char_or_byte(&mut src.chars(), Char)
+}
+
+/// Takes a contents of a byte literal (without quotes), and returns an
+/// unescaped byte or an error.
+pub fn unescape_byte(src: &str) -> Result<u8, EscapeError> {
+    unescape_char_or_byte(&mut src.chars(), Byte).map(byte_from_char)
+}
+
+/// What kind of literal do we parse.
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum Mode {
+    Char,
+
+    Byte,
+
+    Str,
+    RawStr,
+
+    ByteStr,
+    RawByteStr,
+
+    CStr,
+    RawCStr,
+}
+
+impl Mode {
+    pub fn in_double_quotes(self) -> bool {
+        match self {
+            Str | RawStr | ByteStr | RawByteStr | CStr | RawCStr => true,
+            Char | Byte => false,
+        }
+    }
+
+    /// Are `\x80`..`\xff` allowed?
+    fn allow_high_bytes(self) -> bool {
+        match self {
+            Char | Str => false,
+            Byte | ByteStr | CStr => true,
+            RawStr | RawByteStr | RawCStr => unreachable!(),
+        }
+    }
+
+    /// Are unicode (non-ASCII) chars allowed?
+    #[inline]
+    fn allow_unicode_chars(self) -> bool {
+        match self {
+            Byte | ByteStr | RawByteStr => false,
+            Char | Str | RawStr | CStr | RawCStr => true,
+        }
+    }
+
+    /// Are unicode escapes (`\u`) allowed?
+    fn allow_unicode_escapes(self) -> bool {
+        match self {
+            Byte | ByteStr => false,
+            Char | Str | CStr => true,
+            RawByteStr | RawStr | RawCStr => unreachable!(),
+        }
+    }
+
+    pub fn prefix_noraw(self) -> &'static str {
+        match self {
+            Char | Str | RawStr => "",
+            Byte | ByteStr | RawByteStr => "b",
+            CStr | RawCStr => "c",
+        }
+    }
+}
+
+fn scan_escape<T: From<char> + From<u8>>(
+    chars: &mut Chars<'_>,
+    mode: Mode,
+) -> Result<T, EscapeError> {
+    // Previous character was '\\', unescape what follows.
+    let res: char = match chars.next().ok_or(EscapeError::LoneSlash)? {
+        '"' => '"',
+        'n' => '\n',
+        'r' => '\r',
+        't' => '\t',
+        '\\' => '\\',
+        '\'' => '\'',
+        '0' => '\0',
+        'x' => {
+            // Parse hexadecimal character code.
+
+            let hi = chars.next().ok_or(EscapeError::TooShortHexEscape)?;
+            let hi = hi.to_digit(16).ok_or(EscapeError::InvalidCharInHexEscape)?;
+
+            let lo = chars.next().ok_or(EscapeError::TooShortHexEscape)?;
+            let lo = lo.to_digit(16).ok_or(EscapeError::InvalidCharInHexEscape)?;
+
+            let value = (hi * 16 + lo) as u8;
+
+            return if !mode.allow_high_bytes() && !value.is_ascii() {
+                Err(EscapeError::OutOfRangeHexEscape)
+            } else {
+                // This may be a high byte, but that will only happen if `T` is
+                // `MixedUnit`, because of the `allow_high_bytes` check above.
+                Ok(T::from(value))
+            };
+        }
+        'u' => return scan_unicode(chars, mode.allow_unicode_escapes()).map(T::from),
+        _ => return Err(EscapeError::InvalidEscape),
+    };
+    Ok(T::from(res))
+}
+
+fn scan_unicode(chars: &mut Chars<'_>, allow_unicode_escapes: bool) -> Result<char, EscapeError> {
+    // We've parsed '\u', now we have to parse '{..}'.
+
+    if chars.next() != Some('{') {
+        return Err(EscapeError::NoBraceInUnicodeEscape);
+    }
+
+    // First character must be a hexadecimal digit.
+    let mut n_digits = 1;
+    let mut value: u32 = match chars.next().ok_or(EscapeError::UnclosedUnicodeEscape)? {
+        '_' => return Err(EscapeError::LeadingUnderscoreUnicodeEscape),
+        '}' => return Err(EscapeError::EmptyUnicodeEscape),
+        c => c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?,
+    };
+
+    // First character is valid, now parse the rest of the number
+    // and closing brace.
+    loop {
+        match chars.next() {
+            None => return Err(EscapeError::UnclosedUnicodeEscape),
+            Some('_') => continue,
+            Some('}') => {
+                if n_digits > 6 {
+                    return Err(EscapeError::OverlongUnicodeEscape);
+                }
+
+                // Incorrect syntax has higher priority for error reporting
+                // than unallowed value for a literal.
+                if !allow_unicode_escapes {
+                    return Err(EscapeError::UnicodeEscapeInByte);
+                }
+
+                break std::char::from_u32(value).ok_or({
+                    if value > 0x10FFFF {
+                        EscapeError::OutOfRangeUnicodeEscape
+                    } else {
+                        EscapeError::LoneSurrogateUnicodeEscape
+                    }
+                });
+            }
+            Some(c) => {
+                let digit: u32 = c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?;
+                n_digits += 1;
+                if n_digits > 6 {
+                    // Stop updating value since we're sure that it's incorrect already.
+                    continue;
+                }
+                value = value * 16 + digit;
+            }
+        };
+    }
+}
+
+#[inline]
+fn ascii_check(c: char, allow_unicode_chars: bool) -> Result<char, EscapeError> {
+    if allow_unicode_chars || c.is_ascii() { Ok(c) } else { Err(EscapeError::NonAsciiCharInByte) }
+}
+
+fn unescape_char_or_byte(chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> {
+    let c = chars.next().ok_or(EscapeError::ZeroChars)?;
+    let res = match c {
+        '\\' => scan_escape(chars, mode),
+        '\n' | '\t' | '\'' => Err(EscapeError::EscapeOnlyChar),
+        '\r' => Err(EscapeError::BareCarriageReturn),
+        _ => ascii_check(c, mode.allow_unicode_chars()),
+    }?;
+    if chars.next().is_some() {
+        return Err(EscapeError::MoreThanOneChar);
+    }
+    Ok(res)
+}
+
+/// Takes a contents of a string literal (without quotes) and produces a
+/// sequence of escaped characters or errors.
+fn unescape_non_raw_common<F, T: From<char> + From<u8>>(src: &str, mode: Mode, callback: &mut F)
+where
+    F: FnMut(Range<usize>, Result<T, EscapeError>),
+{
+    let mut chars = src.chars();
+    let allow_unicode_chars = mode.allow_unicode_chars(); // get this outside the loop
+
+    // The `start` and `end` computation here is complicated because
+    // `skip_ascii_whitespace` makes us to skip over chars without counting
+    // them in the range computation.
+    while let Some(c) = chars.next() {
+        let start = src.len() - chars.as_str().len() - c.len_utf8();
+        let res = match c {
+            '\\' => {
+                match chars.clone().next() {
+                    Some('\n') => {
+                        // Rust language specification requires us to skip whitespaces
+                        // if unescaped '\' character is followed by '\n'.
+                        // For details see [Rust language reference]
+                        // (https://doc.rust-lang.org/reference/tokens.html#string-literals).
+                        skip_ascii_whitespace(&mut chars, start, &mut |range, err| {
+                            callback(range, Err(err))
+                        });
+                        continue;
+                    }
+                    _ => scan_escape::<T>(&mut chars, mode),
+                }
+            }
+            '"' => Err(EscapeError::EscapeOnlyChar),
+            '\r' => Err(EscapeError::BareCarriageReturn),
+            _ => ascii_check(c, allow_unicode_chars).map(T::from),
+        };
+        let end = src.len() - chars.as_str().len();
+        callback(start..end, res);
+    }
+}
+
+fn skip_ascii_whitespace<F>(chars: &mut Chars<'_>, start: usize, callback: &mut F)
+where
+    F: FnMut(Range<usize>, EscapeError),
+{
+    let tail = chars.as_str();
+    let first_non_space = tail
+        .bytes()
+        .position(|b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r')
+        .unwrap_or(tail.len());
+    if tail[1..first_non_space].contains('\n') {
+        // The +1 accounts for the escaping slash.
+        let end = start + first_non_space + 1;
+        callback(start..end, EscapeError::MultipleSkippedLinesWarning);
+    }
+    let tail = &tail[first_non_space..];
+    if let Some(c) = tail.chars().next() {
+        if c.is_whitespace() {
+            // For error reporting, we would like the span to contain the character that was not
+            // skipped. The +1 is necessary to account for the leading \ that started the escape.
+            let end = start + first_non_space + c.len_utf8() + 1;
+            callback(start..end, EscapeError::UnskippedWhitespaceWarning);
+        }
+    }
+    *chars = tail.chars();
+}
+
+/// Takes a contents of a string literal (without quotes) and produces a
+/// sequence of characters or errors.
+/// NOTE: Raw strings do not perform any explicit character escaping, here we
+/// only produce errors on bare CR.
+fn check_raw_common<F>(src: &str, mode: Mode, callback: &mut F)
+where
+    F: FnMut(Range<usize>, Result<char, EscapeError>),
+{
+    let mut chars = src.chars();
+    let allow_unicode_chars = mode.allow_unicode_chars(); // get this outside the loop
+
+    // The `start` and `end` computation here matches the one in
+    // `unescape_non_raw_common` for consistency, even though this function
+    // doesn't have to worry about skipping any chars.
+    while let Some(c) = chars.next() {
+        let start = src.len() - chars.as_str().len() - c.len_utf8();
+        let res = match c {
+            '\r' => Err(EscapeError::BareCarriageReturnInRawString),
+            _ => ascii_check(c, allow_unicode_chars),
+        };
+        let end = src.len() - chars.as_str().len();
+        callback(start..end, res);
+    }
+}
+
+#[inline]
+pub fn byte_from_char(c: char) -> u8 {
+    let res = c as u32;
+    debug_assert!(res <= u8::MAX as u32, "guaranteed because of ByteStr");
+    res as u8
+}
diff --git a/compiler/rustc_lexer/src/unescape/tests.rs b/compiler/rustc_lexer/src/unescape/tests.rs
new file mode 100644
index 00000000000..5b99495f475
--- /dev/null
+++ b/compiler/rustc_lexer/src/unescape/tests.rs
@@ -0,0 +1,286 @@
+use super::*;
+
+#[test]
+fn test_unescape_char_bad() {
+    fn check(literal_text: &str, expected_error: EscapeError) {
+        assert_eq!(unescape_char(literal_text), Err(expected_error));
+    }
+
+    check("", EscapeError::ZeroChars);
+    check(r"\", EscapeError::LoneSlash);
+
+    check("\n", EscapeError::EscapeOnlyChar);
+    check("\t", EscapeError::EscapeOnlyChar);
+    check("'", EscapeError::EscapeOnlyChar);
+    check("\r", EscapeError::BareCarriageReturn);
+
+    check("spam", EscapeError::MoreThanOneChar);
+    check(r"\x0ff", EscapeError::MoreThanOneChar);
+    check(r#"\"a"#, EscapeError::MoreThanOneChar);
+    check(r"\na", EscapeError::MoreThanOneChar);
+    check(r"\ra", EscapeError::MoreThanOneChar);
+    check(r"\ta", EscapeError::MoreThanOneChar);
+    check(r"\\a", EscapeError::MoreThanOneChar);
+    check(r"\'a", EscapeError::MoreThanOneChar);
+    check(r"\0a", EscapeError::MoreThanOneChar);
+    check(r"\u{0}x", EscapeError::MoreThanOneChar);
+    check(r"\u{1F63b}}", EscapeError::MoreThanOneChar);
+
+    check(r"\v", EscapeError::InvalidEscape);
+    check(r"\💩", EscapeError::InvalidEscape);
+    check(r"\●", EscapeError::InvalidEscape);
+    check("\\\r", EscapeError::InvalidEscape);
+
+    check(r"\x", EscapeError::TooShortHexEscape);
+    check(r"\x0", EscapeError::TooShortHexEscape);
+    check(r"\xf", EscapeError::TooShortHexEscape);
+    check(r"\xa", EscapeError::TooShortHexEscape);
+    check(r"\xx", EscapeError::InvalidCharInHexEscape);
+    check(r"\xы", EscapeError::InvalidCharInHexEscape);
+    check(r"\x🦀", EscapeError::InvalidCharInHexEscape);
+    check(r"\xtt", EscapeError::InvalidCharInHexEscape);
+    check(r"\xff", EscapeError::OutOfRangeHexEscape);
+    check(r"\xFF", EscapeError::OutOfRangeHexEscape);
+    check(r"\x80", EscapeError::OutOfRangeHexEscape);
+
+    check(r"\u", EscapeError::NoBraceInUnicodeEscape);
+    check(r"\u[0123]", EscapeError::NoBraceInUnicodeEscape);
+    check(r"\u{0x}", EscapeError::InvalidCharInUnicodeEscape);
+    check(r"\u{", EscapeError::UnclosedUnicodeEscape);
+    check(r"\u{0000", EscapeError::UnclosedUnicodeEscape);
+    check(r"\u{}", EscapeError::EmptyUnicodeEscape);
+    check(r"\u{_0000}", EscapeError::LeadingUnderscoreUnicodeEscape);
+    check(r"\u{0000000}", EscapeError::OverlongUnicodeEscape);
+    check(r"\u{FFFFFF}", EscapeError::OutOfRangeUnicodeEscape);
+    check(r"\u{ffffff}", EscapeError::OutOfRangeUnicodeEscape);
+    check(r"\u{ffffff}", EscapeError::OutOfRangeUnicodeEscape);
+
+    check(r"\u{DC00}", EscapeError::LoneSurrogateUnicodeEscape);
+    check(r"\u{DDDD}", EscapeError::LoneSurrogateUnicodeEscape);
+    check(r"\u{DFFF}", EscapeError::LoneSurrogateUnicodeEscape);
+
+    check(r"\u{D800}", EscapeError::LoneSurrogateUnicodeEscape);
+    check(r"\u{DAAA}", EscapeError::LoneSurrogateUnicodeEscape);
+    check(r"\u{DBFF}", EscapeError::LoneSurrogateUnicodeEscape);
+}
+
+#[test]
+fn test_unescape_char_good() {
+    fn check(literal_text: &str, expected_char: char) {
+        assert_eq!(unescape_char(literal_text), Ok(expected_char));
+    }
+
+    check("a", 'a');
+    check("ы", 'ы');
+    check("🦀", '🦀');
+
+    check(r#"\""#, '"');
+    check(r"\n", '\n');
+    check(r"\r", '\r');
+    check(r"\t", '\t');
+    check(r"\\", '\\');
+    check(r"\'", '\'');
+    check(r"\0", '\0');
+
+    check(r"\x00", '\0');
+    check(r"\x5a", 'Z');
+    check(r"\x5A", 'Z');
+    check(r"\x7f", 127 as char);
+
+    check(r"\u{0}", '\0');
+    check(r"\u{000000}", '\0');
+    check(r"\u{41}", 'A');
+    check(r"\u{0041}", 'A');
+    check(r"\u{00_41}", 'A');
+    check(r"\u{4__1__}", 'A');
+    check(r"\u{1F63b}", '😻');
+}
+
+#[test]
+fn test_unescape_str_warn() {
+    fn check(literal: &str, expected: &[(Range<usize>, Result<char, EscapeError>)]) {
+        let mut unescaped = Vec::with_capacity(literal.len());
+        unescape_unicode(literal, Mode::Str, &mut |range, res| unescaped.push((range, res)));
+        assert_eq!(unescaped, expected);
+    }
+
+    // Check we can handle escaped newlines at the end of a file.
+    check("\\\n", &[]);
+    check("\\\n ", &[]);
+
+    check(
+        "\\\n \u{a0} x",
+        &[
+            (0..5, Err(EscapeError::UnskippedWhitespaceWarning)),
+            (3..5, Ok('\u{a0}')),
+            (5..6, Ok(' ')),
+            (6..7, Ok('x')),
+        ],
+    );
+    check("\\\n  \n  x", &[(0..7, Err(EscapeError::MultipleSkippedLinesWarning)), (7..8, Ok('x'))]);
+}
+
+#[test]
+fn test_unescape_str_good() {
+    fn check(literal_text: &str, expected: &str) {
+        let mut buf = Ok(String::with_capacity(literal_text.len()));
+        unescape_unicode(literal_text, Mode::Str, &mut |range, c| {
+            if let Ok(b) = &mut buf {
+                match c {
+                    Ok(c) => b.push(c),
+                    Err(e) => buf = Err((range, e)),
+                }
+            }
+        });
+        assert_eq!(buf.as_deref(), Ok(expected))
+    }
+
+    check("foo", "foo");
+    check("", "");
+    check(" \t\n", " \t\n");
+
+    check("hello \\\n     world", "hello world");
+    check("thread's", "thread's")
+}
+
+#[test]
+fn test_unescape_byte_bad() {
+    fn check(literal_text: &str, expected_error: EscapeError) {
+        assert_eq!(unescape_byte(literal_text), Err(expected_error));
+    }
+
+    check("", EscapeError::ZeroChars);
+    check(r"\", EscapeError::LoneSlash);
+
+    check("\n", EscapeError::EscapeOnlyChar);
+    check("\t", EscapeError::EscapeOnlyChar);
+    check("'", EscapeError::EscapeOnlyChar);
+    check("\r", EscapeError::BareCarriageReturn);
+
+    check("spam", EscapeError::MoreThanOneChar);
+    check(r"\x0ff", EscapeError::MoreThanOneChar);
+    check(r#"\"a"#, EscapeError::MoreThanOneChar);
+    check(r"\na", EscapeError::MoreThanOneChar);
+    check(r"\ra", EscapeError::MoreThanOneChar);
+    check(r"\ta", EscapeError::MoreThanOneChar);
+    check(r"\\a", EscapeError::MoreThanOneChar);
+    check(r"\'a", EscapeError::MoreThanOneChar);
+    check(r"\0a", EscapeError::MoreThanOneChar);
+
+    check(r"\v", EscapeError::InvalidEscape);
+    check(r"\💩", EscapeError::InvalidEscape);
+    check(r"\●", EscapeError::InvalidEscape);
+
+    check(r"\x", EscapeError::TooShortHexEscape);
+    check(r"\x0", EscapeError::TooShortHexEscape);
+    check(r"\xa", EscapeError::TooShortHexEscape);
+    check(r"\xf", EscapeError::TooShortHexEscape);
+    check(r"\xx", EscapeError::InvalidCharInHexEscape);
+    check(r"\xы", EscapeError::InvalidCharInHexEscape);
+    check(r"\x🦀", EscapeError::InvalidCharInHexEscape);
+    check(r"\xtt", EscapeError::InvalidCharInHexEscape);
+
+    check(r"\u", EscapeError::NoBraceInUnicodeEscape);
+    check(r"\u[0123]", EscapeError::NoBraceInUnicodeEscape);
+    check(r"\u{0x}", EscapeError::InvalidCharInUnicodeEscape);
+    check(r"\u{", EscapeError::UnclosedUnicodeEscape);
+    check(r"\u{0000", EscapeError::UnclosedUnicodeEscape);
+    check(r"\u{}", EscapeError::EmptyUnicodeEscape);
+    check(r"\u{_0000}", EscapeError::LeadingUnderscoreUnicodeEscape);
+    check(r"\u{0000000}", EscapeError::OverlongUnicodeEscape);
+
+    check("ы", EscapeError::NonAsciiCharInByte);
+    check("🦀", EscapeError::NonAsciiCharInByte);
+
+    check(r"\u{0}", EscapeError::UnicodeEscapeInByte);
+    check(r"\u{000000}", EscapeError::UnicodeEscapeInByte);
+    check(r"\u{41}", EscapeError::UnicodeEscapeInByte);
+    check(r"\u{0041}", EscapeError::UnicodeEscapeInByte);
+    check(r"\u{00_41}", EscapeError::UnicodeEscapeInByte);
+    check(r"\u{4__1__}", EscapeError::UnicodeEscapeInByte);
+    check(r"\u{1F63b}", EscapeError::UnicodeEscapeInByte);
+    check(r"\u{0}x", EscapeError::UnicodeEscapeInByte);
+    check(r"\u{1F63b}}", EscapeError::UnicodeEscapeInByte);
+    check(r"\u{FFFFFF}", EscapeError::UnicodeEscapeInByte);
+    check(r"\u{ffffff}", EscapeError::UnicodeEscapeInByte);
+    check(r"\u{ffffff}", EscapeError::UnicodeEscapeInByte);
+    check(r"\u{DC00}", EscapeError::UnicodeEscapeInByte);
+    check(r"\u{DDDD}", EscapeError::UnicodeEscapeInByte);
+    check(r"\u{DFFF}", EscapeError::UnicodeEscapeInByte);
+    check(r"\u{D800}", EscapeError::UnicodeEscapeInByte);
+    check(r"\u{DAAA}", EscapeError::UnicodeEscapeInByte);
+    check(r"\u{DBFF}", EscapeError::UnicodeEscapeInByte);
+}
+
+#[test]
+fn test_unescape_byte_good() {
+    fn check(literal_text: &str, expected_byte: u8) {
+        assert_eq!(unescape_byte(literal_text), Ok(expected_byte));
+    }
+
+    check("a", b'a');
+
+    check(r#"\""#, b'"');
+    check(r"\n", b'\n');
+    check(r"\r", b'\r');
+    check(r"\t", b'\t');
+    check(r"\\", b'\\');
+    check(r"\'", b'\'');
+    check(r"\0", b'\0');
+
+    check(r"\x00", b'\0');
+    check(r"\x5a", b'Z');
+    check(r"\x5A", b'Z');
+    check(r"\x7f", 127);
+    check(r"\x80", 128);
+    check(r"\xff", 255);
+    check(r"\xFF", 255);
+}
+
+#[test]
+fn test_unescape_byte_str_good() {
+    fn check(literal_text: &str, expected: &[u8]) {
+        let mut buf = Ok(Vec::with_capacity(literal_text.len()));
+        unescape_unicode(literal_text, Mode::ByteStr, &mut |range, c| {
+            if let Ok(b) = &mut buf {
+                match c {
+                    Ok(c) => b.push(byte_from_char(c)),
+                    Err(e) => buf = Err((range, e)),
+                }
+            }
+        });
+        assert_eq!(buf.as_deref(), Ok(expected))
+    }
+
+    check("foo", b"foo");
+    check("", b"");
+    check(" \t\n", b" \t\n");
+
+    check("hello \\\n     world", b"hello world");
+    check("thread's", b"thread's")
+}
+
+#[test]
+fn test_unescape_raw_str() {
+    fn check(literal: &str, expected: &[(Range<usize>, Result<char, EscapeError>)]) {
+        let mut unescaped = Vec::with_capacity(literal.len());
+        unescape_unicode(literal, Mode::RawStr, &mut |range, res| unescaped.push((range, res)));
+        assert_eq!(unescaped, expected);
+    }
+
+    check("\r", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString))]);
+    check("\rx", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString)), (1..2, Ok('x'))]);
+}
+
+#[test]
+fn test_unescape_raw_byte_str() {
+    fn check(literal: &str, expected: &[(Range<usize>, Result<char, EscapeError>)]) {
+        let mut unescaped = Vec::with_capacity(literal.len());
+        unescape_unicode(literal, Mode::RawByteStr, &mut |range, res| unescaped.push((range, res)));
+        assert_eq!(unescaped, expected);
+    }
+
+    check("\r", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString))]);
+    check("🦀", &[(0..4, Err(EscapeError::NonAsciiCharInByte))]);
+    check("🦀a", &[(0..4, Err(EscapeError::NonAsciiCharInByte)), (4..5, Ok('a'))]);
+}
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index 8c6b11a681e..e26575b552e 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -194,7 +194,6 @@ pub struct Mapping {
 #[derive(TyEncodable, TyDecodable, Hash, HashStable)]
 pub struct FunctionCoverageInfo {
     pub function_source_hash: u64,
-    pub body_span: Span,
 
     /// Used in conjunction with `priority_list` to create physical counters
     /// and counter expressions, after MIR optimizations.
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 573f7895da2..5a038b27337 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -620,9 +620,8 @@ fn write_function_coverage_info(
     function_coverage_info: &coverage::FunctionCoverageInfo,
     w: &mut dyn io::Write,
 ) -> io::Result<()> {
-    let coverage::FunctionCoverageInfo { body_span, mappings, .. } = function_coverage_info;
+    let coverage::FunctionCoverageInfo { mappings, .. } = function_coverage_info;
 
-    writeln!(w, "{INDENT}coverage body span: {body_span:?}")?;
     for coverage::Mapping { kind, span } in mappings {
         writeln!(w, "{INDENT}coverage {kind:?} => {span:?};")?;
     }
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index b99148f3368..980d20f9d3b 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -712,10 +712,7 @@ impl<'tcx> Instance<'tcx> {
                             ..
                         })
                     );
-                // We also need to generate a shim if this is an AFIT.
-                let needs_rpitit_shim =
-                    tcx.return_position_impl_trait_in_trait_shim_data(def).is_some();
-                if needs_track_caller_shim || needs_rpitit_shim {
+                if needs_track_caller_shim {
                     if tcx.is_closure_like(def) {
                         debug!(
                             " => vtable fn pointer created for closure with #[track_caller]: {:?} for method {:?} {:?}",
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index a508487c796..fc439416a1a 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -149,7 +149,6 @@ mod opaque_types;
 mod parameterized;
 mod predicate;
 mod region;
-mod return_position_impl_trait_in_trait;
 mod rvalue_scopes;
 mod structural_impls;
 #[allow(hidden_glob_reexports)]
diff --git a/compiler/rustc_middle/src/ty/return_position_impl_trait_in_trait.rs b/compiler/rustc_middle/src/ty/return_position_impl_trait_in_trait.rs
deleted file mode 100644
index 568e504b940..00000000000
--- a/compiler/rustc_middle/src/ty/return_position_impl_trait_in_trait.rs
+++ /dev/null
@@ -1,95 +0,0 @@
-use rustc_hir::def_id::DefId;
-
-use crate::ty::{self, ExistentialPredicateStableCmpExt, TyCtxt};
-
-impl<'tcx> TyCtxt<'tcx> {
-    /// Given a `def_id` of a trait or impl method, compute whether that method needs to
-    /// have an RPITIT shim applied to it for it to be dyn compatible. If so, return the
-    /// `def_id` of the RPITIT, and also the args of trait method that returns the RPITIT.
-    ///
-    /// NOTE that these args are not, in general, the same as than the RPITIT's args. They
-    /// are a subset of those args,  since they do not include the late-bound lifetimes of
-    /// the RPITIT. Depending on the context, these will need to be dealt with in different
-    /// ways -- in codegen, it's okay to fill them with ReErased.
-    pub fn return_position_impl_trait_in_trait_shim_data(
-        self,
-        def_id: DefId,
-    ) -> Option<(DefId, ty::EarlyBinder<'tcx, ty::GenericArgsRef<'tcx>>)> {
-        let assoc_item = self.opt_associated_item(def_id)?;
-
-        let (trait_item_def_id, opt_impl_def_id) = match assoc_item.container {
-            ty::AssocItemContainer::Impl => {
-                (assoc_item.trait_item_def_id?, Some(self.parent(def_id)))
-            }
-            ty::AssocItemContainer::Trait => (def_id, None),
-        };
-
-        let sig = self.fn_sig(trait_item_def_id);
-
-        // Check if the trait returns an RPITIT.
-        let ty::Alias(ty::Projection, ty::AliasTy { def_id, .. }) =
-            *sig.skip_binder().skip_binder().output().kind()
-        else {
-            return None;
-        };
-        if !self.is_impl_trait_in_trait(def_id) {
-            return None;
-        }
-
-        let args = if let Some(impl_def_id) = opt_impl_def_id {
-            // Rebase the args from the RPITIT onto the impl trait ref, so we can later
-            // substitute them with the method args of the *impl* method, since that's
-            // the instance we're building a vtable shim for.
-            ty::GenericArgs::identity_for_item(self, trait_item_def_id).rebase_onto(
-                self,
-                self.parent(trait_item_def_id),
-                self.impl_trait_ref(impl_def_id)
-                    .expect("expected impl trait ref from parent of impl item")
-                    .instantiate_identity()
-                    .args,
-            )
-        } else {
-            // This is when we have a default trait implementation.
-            ty::GenericArgs::identity_for_item(self, trait_item_def_id)
-        };
-
-        Some((def_id, ty::EarlyBinder::bind(args)))
-    }
-
-    /// Given a `DefId` of an RPITIT and its args, return the existential predicates
-    /// that corresponds to the RPITIT's bounds with the self type erased.
-    pub fn item_bounds_to_existential_predicates(
-        self,
-        def_id: DefId,
-        args: ty::GenericArgsRef<'tcx>,
-    ) -> &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
-        let mut bounds: Vec<_> = self
-            .item_self_bounds(def_id)
-            .iter_instantiated(self, args)
-            .filter_map(|clause| {
-                clause
-                    .kind()
-                    .map_bound(|clause| match clause {
-                        ty::ClauseKind::Trait(trait_pred) => Some(ty::ExistentialPredicate::Trait(
-                            ty::ExistentialTraitRef::erase_self_ty(self, trait_pred.trait_ref),
-                        )),
-                        ty::ClauseKind::Projection(projection_pred) => {
-                            Some(ty::ExistentialPredicate::Projection(
-                                ty::ExistentialProjection::erase_self_ty(self, projection_pred),
-                            ))
-                        }
-                        ty::ClauseKind::TypeOutlives(_) => {
-                            // Type outlives bounds don't really turn into anything,
-                            // since we must use an intersection region for the `dyn*`'s
-                            // region anyways.
-                            None
-                        }
-                        _ => unreachable!("unexpected clause in item bounds: {clause:?}"),
-                    })
-                    .transpose()
-            })
-            .collect();
-        bounds.sort_by(|a, b| a.skip_binder().stable_cmp(self, &b.skip_binder()));
-        self.mk_poly_existential_predicates(&bounds)
-    }
-}
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 1ccae0fd7fe..572dbae8fd2 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -107,7 +107,6 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
 
     mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
         function_source_hash: hir_info.function_source_hash,
-        body_span: hir_info.body_span,
 
         node_flow_data,
         priority_list,
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 34074a84e28..c9771467e49 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -8,7 +8,6 @@ use rustc_hir::lang_items::LangItem;
 use rustc_index::{Idx, IndexVec};
 use rustc_middle::mir::*;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::{
     self, CoroutineArgs, CoroutineArgsExt, EarlyBinder, GenericArgs, Ty, TyCtxt,
 };
@@ -718,12 +717,6 @@ fn build_call_shim<'tcx>(
 
     let def_id = instance.def_id();
 
-    let rpitit_shim = if let ty::InstanceKind::ReifyShim(..) = instance {
-        tcx.return_position_impl_trait_in_trait_shim_data(def_id)
-    } else {
-        None
-    };
-
     let sig = tcx.fn_sig(def_id);
     let sig = sig.map_bound(|sig| tcx.instantiate_bound_regions_with_erased(sig));
 
@@ -779,30 +772,7 @@ fn build_call_shim<'tcx>(
     let mut local_decls = local_decls_for_sig(&sig, span);
     let source_info = SourceInfo::outermost(span);
 
-    let mut destination = Place::return_place();
-    if let Some((rpitit_def_id, fn_args)) = rpitit_shim {
-        let rpitit_args =
-            fn_args.instantiate_identity().extend_to(tcx, rpitit_def_id, |param, _| {
-                match param.kind {
-                    ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
-                    ty::GenericParamDefKind::Type { .. }
-                    | ty::GenericParamDefKind::Const { .. } => {
-                        unreachable!("rpitit should have no addition ty/ct")
-                    }
-                }
-            });
-        let dyn_star_ty = Ty::new_dynamic(
-            tcx,
-            tcx.item_bounds_to_existential_predicates(rpitit_def_id, rpitit_args),
-            tcx.lifetimes.re_erased,
-            ty::DynStar,
-        );
-        destination = local_decls.push(local_decls[RETURN_PLACE].clone()).into();
-        local_decls[RETURN_PLACE].ty = dyn_star_ty;
-        let mut inputs_and_output = sig.inputs_and_output.to_vec();
-        *inputs_and_output.last_mut().unwrap() = dyn_star_ty;
-        sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output);
-    }
+    let destination = Place::return_place();
 
     let rcvr_place = || {
         assert!(rcvr_adjustment.is_some());
@@ -921,23 +891,7 @@ fn build_call_shim<'tcx>(
         );
     }
     // BB #1/#2 - return
-    // NOTE: If this is an RPITIT in dyn, we also want to coerce
-    // the return type of the function into a `dyn*`.
-    let stmts = if rpitit_shim.is_some() {
-        vec![Statement {
-            source_info,
-            kind: StatementKind::Assign(Box::new((
-                Place::return_place(),
-                Rvalue::Cast(
-                    CastKind::PointerCoercion(PointerCoercion::DynStar, CoercionSource::Implicit),
-                    Operand::Move(destination),
-                    sig.output(),
-                ),
-            ))),
-        }]
-    } else {
-        vec![]
-    };
+    let stmts = vec![];
     block(&mut blocks, stmts, TerminatorKind::Return, false);
     if let Some(Adjustment::RefMut) = rcvr_adjustment {
         // BB #3 - drop if closure panics
diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml
index e83f2d5a56d..c9dcab0c871 100644
--- a/compiler/rustc_parse/Cargo.toml
+++ b/compiler/rustc_parse/Cargo.toml
@@ -6,7 +6,6 @@ edition = "2024"
 [dependencies]
 # tidy-alphabetical-start
 bitflags = "2.4.1"
-literal-escaper = { path = "../../library/literal-escaper" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_data_structures = { path = "../rustc_data_structures" }
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 4a3fda86c86..1d17290e1c7 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -1,12 +1,12 @@
 use std::ops::Range;
 
-use literal_escaper::{self, EscapeError, Mode};
 use rustc_ast::ast::{self, AttrStyle};
 use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::util::unicode::contains_text_flow_control_chars;
 use rustc_errors::codes::*;
 use rustc_errors::{Applicability, Diag, DiagCtxtHandle, StashKey};
+use rustc_lexer::unescape::{self, EscapeError, Mode};
 use rustc_lexer::{Base, Cursor, DocStyle, LiteralKind, RawStrError};
 use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::lint::builtin::{
@@ -970,7 +970,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
         postfix_len: u32,
     ) -> (token::LitKind, Symbol) {
         self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| {
-            literal_escaper::unescape_unicode(src, mode, &mut |span, result| {
+            unescape::unescape_unicode(src, mode, &mut |span, result| {
                 callback(span, result.map(drop))
             })
         })
@@ -986,7 +986,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
         postfix_len: u32,
     ) -> (token::LitKind, Symbol) {
         self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| {
-            literal_escaper::unescape_mixed(src, mode, &mut |span, result| {
+            unescape::unescape_mixed(src, mode, &mut |span, result| {
                 callback(span, result.map(drop))
             })
         })
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index e8aa400e73d..2e066f0179c 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -3,8 +3,8 @@
 use std::iter::once;
 use std::ops::Range;
 
-use literal_escaper::{EscapeError, Mode};
 use rustc_errors::{Applicability, DiagCtxtHandle, ErrorGuaranteed};
+use rustc_lexer::unescape::{EscapeError, Mode};
 use rustc_span::{BytePos, Span};
 use tracing::debug;
 
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 85d94400b1c..0774324eae7 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -6,7 +6,6 @@ use core::ops::{Bound, ControlFlow};
 use ast::mut_visit::{self, MutVisitor};
 use ast::token::{IdentIsRaw, MetaVarKind};
 use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment, Recovered};
-use literal_escaper::unescape_char;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::TokenTree;
@@ -22,6 +21,7 @@ use rustc_ast::{
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic};
+use rustc_lexer::unescape::unescape_char;
 use rustc_macros::Subdiagnostic;
 use rustc_session::errors::{ExprParenthesesNeeded, report_lit_error};
 use rustc_session::lint::BuiltinLintDiag;
diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml
index e63ed9e16f2..a39cca716d2 100644
--- a/compiler/rustc_parse_format/Cargo.toml
+++ b/compiler/rustc_parse_format/Cargo.toml
@@ -5,7 +5,6 @@ edition = "2024"
 
 [dependencies]
 # tidy-alphabetical-start
-literal-escaper = { path = "../../library/literal-escaper" }
 rustc_index = { path = "../rustc_index", default-features = false }
 rustc_lexer = { path = "../rustc_lexer" }
 # tidy-alphabetical-end
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 5780daf3034..5b8a2fe52d3 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -18,6 +18,7 @@
 pub use Alignment::*;
 pub use Count::*;
 pub use Position::*;
+use rustc_lexer::unescape;
 
 // Note: copied from rustc_span
 /// Range inside of a `Span` used for diagnostics when we only have access to relative positions.
@@ -1093,14 +1094,12 @@ fn find_width_map_from_snippet(
 fn unescape_string(string: &str) -> Option<String> {
     let mut buf = String::new();
     let mut ok = true;
-    literal_escaper::unescape_unicode(
-        string,
-        literal_escaper::Mode::Str,
-        &mut |_, unescaped_char| match unescaped_char {
+    unescape::unescape_unicode(string, unescape::Mode::Str, &mut |_, unescaped_char| {
+        match unescaped_char {
             Ok(c) => buf.push(c),
             Err(_) => ok = false,
-        },
-    );
+        }
+    });
 
     ok.then_some(buf)
 }
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index 3fceada2510..78a45243983 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -9,7 +9,6 @@ use std::ops::ControlFlow;
 use rustc_errors::FatalError;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{
     self, EarlyBinder, GenericArgs, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
@@ -807,31 +806,8 @@ fn contains_illegal_impl_trait_in_trait<'tcx>(
     let ty = tcx.liberate_late_bound_regions(fn_def_id, ty);
 
     if tcx.asyncness(fn_def_id).is_async() {
-        // FIXME(async_fn_in_dyn_trait): Think of a better way to unify these code paths
-        // to issue an appropriate feature suggestion when users try to use AFIDT.
-        // Obviously we must only do this once AFIDT is finished enough to actually be usable.
-        if tcx.features().async_fn_in_dyn_trait() {
-            let ty::Alias(ty::Projection, proj) = *ty.kind() else {
-                bug!("expected async fn in trait to return an RPITIT");
-            };
-            assert!(tcx.is_impl_trait_in_trait(proj.def_id));
-
-            // FIXME(async_fn_in_dyn_trait): We should check that this bound is legal too,
-            // and stop relying on `async fn` in the definition.
-            for bound in tcx.item_bounds(proj.def_id).instantiate(tcx, proj.args) {
-                if let Some(violation) = bound
-                    .visit_with(&mut IllegalRpititVisitor { tcx, allowed: Some(proj) })
-                    .break_value()
-                {
-                    return Some(violation);
-                }
-            }
-
-            None
-        } else {
-            // Rendering the error as a separate `async-specific` message is better.
-            Some(MethodViolationCode::AsyncFn)
-        }
+        // Rendering the error as a separate `async-specific` message is better.
+        Some(MethodViolationCode::AsyncFn)
     } else {
         ty.visit_with(&mut IllegalRpititVisitor { tcx, allowed: None }).break_value()
     }
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 2c60be63bd5..6057b66c483 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -7,8 +7,8 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::DefKind;
 use rustc_hir::lang_items::LangItem;
+use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
-use rustc_infer::infer::{DefineOpaqueTypes, RegionVariableOrigin};
 use rustc_infer::traits::{ObligationCauseCode, PredicateObligations};
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::traits::{BuiltinImplSource, ImplSource, ImplSourceUserDefinedData};
@@ -18,8 +18,6 @@ use rustc_middle::ty::{
 };
 use rustc_middle::{bug, span_bug};
 use rustc_span::sym;
-use rustc_type_ir::elaborate;
-use thin_vec::thin_vec;
 use tracing::{debug, instrument};
 
 use super::{
@@ -63,9 +61,6 @@ enum ProjectionCandidate<'tcx> {
     /// Bounds specified on an object type
     Object(ty::PolyProjectionPredicate<'tcx>),
 
-    /// Built-in bound for a dyn async fn in trait
-    ObjectRpitit,
-
     /// From an "impl" (or a "pseudo-impl" returned by select)
     Select(Selection<'tcx>),
 }
@@ -832,16 +827,6 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
         env_predicates,
         false,
     );
-
-    // `dyn Trait` automagically project their AFITs to `dyn* Future`.
-    if tcx.is_impl_trait_in_trait(obligation.predicate.def_id)
-        && let Some(out_trait_def_id) = data.principal_def_id()
-        && let rpitit_trait_def_id = tcx.parent(obligation.predicate.def_id)
-        && elaborate::supertrait_def_ids(tcx, out_trait_def_id)
-            .any(|trait_def_id| trait_def_id == rpitit_trait_def_id)
-    {
-        candidate_set.push_candidate(ProjectionCandidate::ObjectRpitit);
-    }
 }
 
 #[instrument(
@@ -1273,8 +1258,6 @@ fn confirm_candidate<'cx, 'tcx>(
         ProjectionCandidate::Select(impl_source) => {
             confirm_select_candidate(selcx, obligation, impl_source)
         }
-
-        ProjectionCandidate::ObjectRpitit => confirm_object_rpitit_candidate(selcx, obligation),
     };
 
     // When checking for cycle during evaluation, we compare predicates with
@@ -2070,45 +2053,6 @@ fn confirm_impl_candidate<'cx, 'tcx>(
     }
 }
 
-fn confirm_object_rpitit_candidate<'cx, 'tcx>(
-    selcx: &mut SelectionContext<'cx, 'tcx>,
-    obligation: &ProjectionTermObligation<'tcx>,
-) -> Progress<'tcx> {
-    let tcx = selcx.tcx();
-    let mut obligations = thin_vec![];
-
-    // Compute an intersection lifetime for all the input components of this GAT.
-    let intersection =
-        selcx.infcx.next_region_var(RegionVariableOrigin::MiscVariable(obligation.cause.span));
-    for component in obligation.predicate.args {
-        match component.unpack() {
-            ty::GenericArgKind::Lifetime(lt) => {
-                obligations.push(obligation.with(tcx, ty::OutlivesPredicate(lt, intersection)));
-            }
-            ty::GenericArgKind::Type(ty) => {
-                obligations.push(obligation.with(tcx, ty::OutlivesPredicate(ty, intersection)));
-            }
-            ty::GenericArgKind::Const(_ct) => {
-                // Consts have no outlives...
-            }
-        }
-    }
-
-    Progress {
-        term: Ty::new_dynamic(
-            tcx,
-            tcx.item_bounds_to_existential_predicates(
-                obligation.predicate.def_id,
-                obligation.predicate.args,
-            ),
-            intersection,
-            ty::DynStar,
-        )
-        .into(),
-        obligations,
-    }
-}
-
 // Get obligations corresponding to the predicates from the where-clause of the
 // associated type itself.
 fn assoc_ty_own_obligations<'cx, 'tcx>(
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 4cd6781ab89..4404324d5cd 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -616,12 +616,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         for assoc_type in assoc_types {
             let defs: &ty::Generics = tcx.generics_of(assoc_type);
 
-            // When `async_fn_in_dyn_trait` is enabled, we don't need to check the
-            // RPITIT for compatibility, since it's not provided by the user.
-            if tcx.features().async_fn_in_dyn_trait() && tcx.is_impl_trait_in_trait(assoc_type) {
-                continue;
-            }
-
             if !defs.own_params.is_empty() {
                 tcx.dcx().span_delayed_bug(
                     obligation.cause.span,
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index a726ebae6fe..48d5a4a0fcb 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -55,31 +55,6 @@ fn fn_sig_for_fn_abi<'tcx>(
                 sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output);
             }
 
-            // Modify `fn() -> impl Future` to `fn() -> dyn* Future`.
-            if let ty::InstanceKind::ReifyShim(def_id, _) = instance.def
-                && let Some((rpitit_def_id, fn_args)) =
-                    tcx.return_position_impl_trait_in_trait_shim_data(def_id)
-            {
-                let fn_args = fn_args.instantiate(tcx, args);
-                let rpitit_args =
-                    fn_args.extend_to(tcx, rpitit_def_id, |param, _| match param.kind {
-                        ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
-                        ty::GenericParamDefKind::Type { .. }
-                        | ty::GenericParamDefKind::Const { .. } => {
-                            unreachable!("rpitit should have no addition ty/ct")
-                        }
-                    });
-                let dyn_star_ty = Ty::new_dynamic(
-                    tcx,
-                    tcx.item_bounds_to_existential_predicates(rpitit_def_id, rpitit_args),
-                    tcx.lifetimes.re_erased,
-                    ty::DynStar,
-                );
-                let mut inputs_and_output = sig.inputs_and_output.to_vec();
-                *inputs_and_output.last_mut().unwrap() = dyn_star_ty;
-                sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output);
-            }
-
             sig
         }
         ty::Closure(def_id, args) => {