about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-08-12 03:05:01 +0000
committerbors <bors@rust-lang.org>2023-08-12 03:05:01 +0000
commitd1fa3e4de38d117c94e1cf0807ed629f679e0cab (patch)
tree3559e983bf46807f9e245684d15b160155c08ae1
parentd8fd588afa24f6fa5259a01b815912710713d62f (diff)
parent4d0501412a3216ee4a495e071f4b5fdf43f56c4e (diff)
Auto merge of #114748 - cuviper:beta-next, r=cuviper
[beta] backport

* Restrict linker version script of proc-macro crates to just its two symbols #114470
* bootstrap: config: fix version comparison bug #114440
* lint/ctypes: only try normalize #113921
* Avoid tls access while iterating through mpsc thread entries #113861
* Substitute types before checking inlining compatibility. #113802
* Revert "fix: bug etc/bash_complettion -> src/etc/... to avoid copy error" #113579
* lint/ctypes: fix () return type checks #113457
* Rename and allow cast_ref_to_mut lint #113422
* Ignore flaky clippy tests. #113621

r? cuviper
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs25
-rw-r--r--compiler/rustc_lint/messages.ftl6
-rw-r--r--compiler/rustc_lint/src/lib.rs6
-rw-r--r--compiler/rustc_lint/src/lints.rs6
-rw-r--r--compiler/rustc_lint/src/reference_casting.rs (renamed from compiler/rustc_lint/src/cast_ref_to_mut.rs)15
-rw-r--r--compiler/rustc_lint/src/types.rs104
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs15
-rw-r--r--library/std/src/sync/mpmc/waker.rs46
-rw-r--r--src/bootstrap/config.rs3
-rw-r--r--src/bootstrap/dist.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/renamed_lints.rs2
-rw-r--r--src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs3
-rw-r--r--src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs3
-rw-r--r--src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs3
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed4
-rw-r--r--src/tools/clippy/tests/ui/rename.rs2
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr4
-rw-r--r--src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.rs2
-rw-r--r--src/tools/miri/tests/fail/modifying_constants.rs2
-rw-r--r--tests/ui/const-generics/issues/issue-100313.rs1
-rw-r--r--tests/ui/const-generics/issues/issue-100313.stderr12
-rw-r--r--tests/ui/lint/lint-ctypes-113436-1.rs28
-rw-r--r--tests/ui/lint/lint-ctypes-113436-1.stderr35
-rw-r--r--tests/ui/lint/lint-ctypes-113436.rs34
-rw-r--r--tests/ui/lint/lint-ctypes-113900.rs12
-rw-r--r--tests/ui/lint/reference_casting.rs (renamed from tests/ui/lint/cast_ref_to_mut.rs)1
-rw-r--r--tests/ui/lint/reference_casting.stderr (renamed from tests/ui/lint/cast_ref_to_mut.stderr)26
-rw-r--r--tests/ui/proc-macro/auxiliary/exports_no_mangle.rs11
-rw-r--r--tests/ui/proc-macro/no-mangle-in-proc-macro-issue-111888.rs22
29 files changed, 306 insertions, 133 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index cd56f85cccd..8ac86fa4b26 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -13,6 +13,7 @@ use std::{env, mem, str};
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_metadata::find_native_static_library;
 use rustc_middle::middle::dependency_format::Linkage;
+use rustc_middle::middle::exported_symbols;
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
@@ -659,8 +660,6 @@ impl<'a> Linker for GccLinker<'a> {
             return;
         }
 
-        // FIXME(#99978) hide #[no_mangle] symbols for proc-macros
-
         let is_windows = self.sess.target.is_like_windows;
         let path = tmpdir.join(if is_windows { "list.def" } else { "list" });
 
@@ -1679,8 +1678,15 @@ pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<St
         return exports.iter().map(ToString::to_string).collect();
     }
 
-    let mut symbols = Vec::new();
+    if let CrateType::ProcMacro = crate_type {
+        exported_symbols_for_proc_macro_crate(tcx)
+    } else {
+        exported_symbols_for_non_proc_macro(tcx, crate_type)
+    }
+}
 
+fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
+    let mut symbols = Vec::new();
     let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
     for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
         if info.level.is_below_threshold(export_threshold) {
@@ -1691,6 +1697,19 @@ pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<St
     symbols
 }
 
+fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<String> {
+    // `exported_symbols` will be empty when !should_codegen.
+    if !tcx.sess.opts.output_types.should_codegen() {
+        return Vec::new();
+    }
+
+    let stable_crate_id = tcx.sess.local_stable_crate_id();
+    let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
+    let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx);
+
+    vec![proc_macro_decls_name, metadata_symbol_name]
+}
+
 pub(crate) fn linked_symbols(
     tcx: TyCtxt<'_>,
     crate_type: CrateType,
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 34b7e09576a..22e22c833ac 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -155,8 +155,6 @@ lint_builtin_unused_doc_comment = unused doc comment
 lint_builtin_while_true = denote infinite loops with `loop {"{"} ... {"}"}`
     .suggestion = use `loop`
 
-lint_cast_ref_to_mut = casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-
 lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name}
 
 lint_check_name_unknown = unknown lint: `{$lint_name}`
@@ -264,8 +262,6 @@ lint_improper_ctypes_char_help = consider using `u32` or `libc::wchar_t` instead
 lint_improper_ctypes_char_reason = the `char` type has no C equivalent
 lint_improper_ctypes_dyn = trait objects have no C equivalent
 
-lint_improper_ctypes_enum_phantomdata = this enum contains a PhantomData field
-
 lint_improper_ctypes_enum_repr_help =
     consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
 
@@ -319,6 +315,8 @@ lint_invalid_nan_comparisons_eq_ne = incorrect NaN comparison, NaN cannot be dir
 
 lint_invalid_nan_comparisons_lt_le_gt_ge = incorrect NaN comparison, NaN is not orderable
 
+lint_invalid_reference_casting = casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
+
 lint_lintpass_by_hand = implementing `LintPass` by hand
     .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead
 
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 5e3f057d428..602071a55e5 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -50,7 +50,6 @@ extern crate tracing;
 
 mod array_into_iter;
 pub mod builtin;
-mod cast_ref_to_mut;
 mod context;
 mod deref_into_dyn_supertrait;
 mod drop_forget_useless;
@@ -77,6 +76,7 @@ mod opaque_hidden_inferred_bound;
 mod pass_by_value;
 mod passes;
 mod redundant_semicolon;
+mod reference_casting;
 mod traits;
 mod types;
 mod unused;
@@ -98,7 +98,6 @@ use rustc_span::Span;
 
 use array_into_iter::ArrayIntoIter;
 use builtin::*;
-use cast_ref_to_mut::*;
 use deref_into_dyn_supertrait::*;
 use drop_forget_useless::*;
 use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
@@ -117,6 +116,7 @@ use noop_method_call::*;
 use opaque_hidden_inferred_bound::*;
 use pass_by_value::*;
 use redundant_semicolon::*;
+use reference_casting::*;
 use traits::*;
 use types::*;
 use unused::*;
@@ -216,7 +216,7 @@ late_lint_methods!(
             BoxPointers: BoxPointers,
             PathStatements: PathStatements,
             LetUnderscore: LetUnderscore,
-            CastRefToMut: CastRefToMut,
+            InvalidReferenceCasting: InvalidReferenceCasting,
             // Depends on referenced function signatures in expressions
             UnusedResults: UnusedResults,
             NonUpperCaseGlobals: NonUpperCaseGlobals,
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 0613ef2c5e9..9260237fbee 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -737,10 +737,10 @@ pub enum InvalidFromUtf8Diag {
     },
 }
 
-// cast_ref_to_mut.rs
+// reference_casting.rs
 #[derive(LintDiagnostic)]
-#[diag(lint_cast_ref_to_mut)]
-pub struct CastRefToMutDiag;
+#[diag(lint_invalid_reference_casting)]
+pub struct InvalidReferenceCastingDiag;
 
 // hidden_unicode_codepoints.rs
 #[derive(LintDiagnostic)]
diff --git a/compiler/rustc_lint/src/cast_ref_to_mut.rs b/compiler/rustc_lint/src/reference_casting.rs
index 84308d48c10..db8d7302a25 100644
--- a/compiler/rustc_lint/src/cast_ref_to_mut.rs
+++ b/compiler/rustc_lint/src/reference_casting.rs
@@ -3,15 +3,16 @@ use rustc_hir::{Expr, ExprKind, MutTy, TyKind, UnOp};
 use rustc_middle::ty;
 use rustc_span::sym;
 
-use crate::{lints::CastRefToMutDiag, LateContext, LateLintPass, LintContext};
+use crate::{lints::InvalidReferenceCastingDiag, LateContext, LateLintPass, LintContext};
 
 declare_lint! {
-    /// The `cast_ref_to_mut` lint checks for casts of `&T` to `&mut T`
+    /// The `invalid_reference_casting` lint checks for casts of `&T` to `&mut T`
     /// without using interior mutability.
     ///
     /// ### Example
     ///
     /// ```rust,compile_fail
+    /// # #![deny(invalid_reference_casting)]
     /// fn x(r: &i32) {
     ///     unsafe {
     ///         *(r as *const i32 as *mut i32) += 1;
@@ -28,14 +29,14 @@ declare_lint! {
     ///
     /// `UnsafeCell` is the only way to obtain aliasable data that is considered
     /// mutable.
-    CAST_REF_TO_MUT,
-    Deny,
+    INVALID_REFERENCE_CASTING,
+    Allow,
     "casts of `&T` to `&mut T` without interior mutability"
 }
 
-declare_lint_pass!(CastRefToMut => [CAST_REF_TO_MUT]);
+declare_lint_pass!(InvalidReferenceCasting => [INVALID_REFERENCE_CASTING]);
 
-impl<'tcx> LateLintPass<'tcx> for CastRefToMut {
+impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         let ExprKind::Unary(UnOp::Deref, e) = &expr.kind else { return; };
 
@@ -66,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for CastRefToMut {
 
         let e = e.peel_blocks();
         if let ty::Ref(..) = cx.typeck_results().node_type(e.hir_id).kind() {
-            cx.emit_spanned_lint(CAST_REF_TO_MUT, expr.span, CastRefToMutDiag);
+            cx.emit_spanned_lint(INVALID_REFERENCE_CASTING, expr.span, InvalidReferenceCastingDiag);
         }
     }
 }
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 2509d493a4c..ed4fb98605c 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -963,12 +963,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         substs: SubstsRef<'tcx>,
     ) -> FfiResult<'tcx> {
         let field_ty = field.ty(self.cx.tcx, substs);
-        if field_ty.has_opaque_types() {
-            self.check_type_for_ffi(cache, field_ty)
-        } else {
-            let field_ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, field_ty);
-            self.check_type_for_ffi(cache, field_ty)
-        }
+        let field_ty = self
+            .cx
+            .tcx
+            .try_normalize_erasing_regions(self.cx.param_env, field_ty)
+            .unwrap_or(field_ty);
+        self.check_type_for_ffi(cache, field_ty)
     }
 
     /// Checks if the given `VariantDef`'s field types are "ffi-safe".
@@ -982,39 +982,43 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
     ) -> FfiResult<'tcx> {
         use FfiResult::*;
 
-        let transparent_safety = def.repr().transparent().then(|| {
-            // Can assume that at most one field is not a ZST, so only check
-            // that field's type for FFI-safety.
+        let transparent_with_all_zst_fields = if def.repr().transparent() {
             if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) {
-                return self.check_field_type_for_ffi(cache, field, substs);
+                // Transparent newtypes have at most one non-ZST field which needs to be checked..
+                match self.check_field_type_for_ffi(cache, field, substs) {
+                    FfiUnsafe { ty, .. } if ty.is_unit() => (),
+                    r => return r,
+                }
+
+                false
             } else {
-                // All fields are ZSTs; this means that the type should behave
-                // like (), which is FFI-unsafe... except if all fields are PhantomData,
-                // which is tested for below
-                FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_struct_zst, help: None }
+                // ..or have only ZST fields, which is FFI-unsafe (unless those fields are all
+                // `PhantomData`).
+                true
             }
-        });
-        // We can't completely trust repr(C) markings; make sure the fields are
-        // actually safe.
+        } else {
+            false
+        };
+
+        // We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
         let mut all_phantom = !variant.fields.is_empty();
         for field in &variant.fields {
-            match self.check_field_type_for_ffi(cache, &field, substs) {
-                FfiSafe => {
-                    all_phantom = false;
-                }
-                FfiPhantom(..) if !def.repr().transparent() && def.is_enum() => {
-                    return FfiUnsafe {
-                        ty,
-                        reason: fluent::lint_improper_ctypes_enum_phantomdata,
-                        help: None,
-                    };
-                }
-                FfiPhantom(..) => {}
-                r => return transparent_safety.unwrap_or(r),
+            all_phantom &= match self.check_field_type_for_ffi(cache, &field, substs) {
+                FfiSafe => false,
+                // `()` fields are FFI-safe!
+                FfiUnsafe { ty, .. } if ty.is_unit() => false,
+                FfiPhantom(..) => true,
+                r @ FfiUnsafe { .. } => return r,
             }
         }
 
-        if all_phantom { FfiPhantom(ty) } else { transparent_safety.unwrap_or(FfiSafe) }
+        if all_phantom {
+            FfiPhantom(ty)
+        } else if transparent_with_all_zst_fields {
+            FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_struct_zst, help: None }
+        } else {
+            FfiSafe
+        }
     }
 
     /// Checks if the given type is "ffi-safe" (has a stable, well-defined
@@ -1217,25 +1221,19 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 }
 
                 let sig = tcx.erase_late_bound_regions(sig);
-                if !sig.output().is_unit() {
-                    let r = self.check_type_for_ffi(cache, sig.output());
-                    match r {
-                        FfiSafe => {}
-                        _ => {
-                            return r;
-                        }
-                    }
-                }
                 for arg in sig.inputs() {
-                    let r = self.check_type_for_ffi(cache, *arg);
-                    match r {
+                    match self.check_type_for_ffi(cache, *arg) {
                         FfiSafe => {}
-                        _ => {
-                            return r;
-                        }
+                        r => return r,
                     }
                 }
-                FfiSafe
+
+                let ret_ty = sig.output();
+                if ret_ty.is_unit() {
+                    return FfiSafe;
+                }
+
+                self.check_type_for_ffi(cache, ret_ty)
             }
 
             ty::Foreign(..) => FfiSafe,
@@ -1317,7 +1315,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         if let Some(ty) = self
             .cx
             .tcx
-            .normalize_erasing_regions(self.cx.param_env, ty)
+            .try_normalize_erasing_regions(self.cx.param_env, ty)
+            .unwrap_or(ty)
             .visit_with(&mut ProhibitOpaqueTypes)
             .break_value()
         {
@@ -1335,16 +1334,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         is_static: bool,
         is_return_type: bool,
     ) {
-        // We have to check for opaque types before `normalize_erasing_regions`,
-        // which will replace opaque types with their underlying concrete type.
         if self.check_for_opaque_ty(sp, ty) {
             // We've already emitted an error due to an opaque type.
             return;
         }
 
-        // it is only OK to use this function because extern fns cannot have
-        // any generic types right now:
-        let ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty);
+        let ty = self.cx.tcx.try_normalize_erasing_regions(self.cx.param_env, ty).unwrap_or(ty);
 
         // C doesn't really support passing arrays by value - the only way to pass an array by value
         // is through a struct. So, first test that the top level isn't an array, and then
@@ -1354,7 +1349,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         }
 
         // Don't report FFI errors for unit return types. This check exists here, and not in
-        // `check_foreign_fn` (where it would make more sense) so that normalization has definitely
+        // the caller (where it would make more sense) so that normalization has definitely
         // happened.
         if is_return_type && ty.is_unit() {
             return;
@@ -1370,9 +1365,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                     None,
                 );
             }
-            // If `ty` is a `repr(transparent)` newtype, and the non-zero-sized type is a generic
-            // argument, which after substitution, is `()`, then this branch can be hit.
-            FfiResult::FfiUnsafe { ty, .. } if is_return_type && ty.is_unit() => {}
             FfiResult::FfiUnsafe { ty, reason, help } => {
                 self.emit_ffi_unsafe_type_lint(ty, sp, reason, help);
             }
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 240beabfc1a..b6578cb259a 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -440,6 +440,10 @@ impl<'tcx> Inliner<'tcx> {
             validation: Ok(()),
         };
 
+        for var_debug_info in callee_body.var_debug_info.iter() {
+            checker.visit_var_debug_info(var_debug_info);
+        }
+
         // Traverse the MIR manually so we can account for the effects of inlining on the CFG.
         let mut work_list = vec![START_BLOCK];
         let mut visited = BitSet::new_empty(callee_body.basic_blocks.len());
@@ -847,7 +851,16 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
         if let ProjectionElem::Field(f, ty) = elem {
             let parent_ty = place_ref.ty(&self.callee_body.local_decls, self.tcx);
             let check_equal = |this: &mut Self, f_ty| {
-                if !util::is_equal_up_to_subtyping(this.tcx, this.param_env, ty, f_ty) {
+                // Fast path if there is nothing to substitute.
+                if ty == f_ty {
+                    return;
+                }
+                let ty = this.instance.subst_mir(this.tcx, ty::EarlyBinder::bind(&ty));
+                let f_ty = this.instance.subst_mir(this.tcx, ty::EarlyBinder::bind(&f_ty));
+                if ty == f_ty {
+                    return;
+                }
+                if !util::is_subtype(this.tcx, this.param_env, ty, f_ty) {
                     trace!(?ty, ?f_ty);
                     this.validation = Err("failed to normalize projection type");
                     return;
diff --git a/library/std/src/sync/mpmc/waker.rs b/library/std/src/sync/mpmc/waker.rs
index 4912ca4f815..9aab1b9417e 100644
--- a/library/std/src/sync/mpmc/waker.rs
+++ b/library/std/src/sync/mpmc/waker.rs
@@ -66,26 +66,32 @@ impl Waker {
     /// Attempts to find another thread's entry, select the operation, and wake it up.
     #[inline]
     pub(crate) fn try_select(&mut self) -> Option<Entry> {
-        self.selectors
-            .iter()
-            .position(|selector| {
-                // Does the entry belong to a different thread?
-                selector.cx.thread_id() != current_thread_id()
-                    && selector // Try selecting this operation.
-                        .cx
-                        .try_select(Selected::Operation(selector.oper))
-                        .is_ok()
-                    && {
-                        // Provide the packet.
-                        selector.cx.store_packet(selector.packet);
-                        // Wake the thread up.
-                        selector.cx.unpark();
-                        true
-                    }
-            })
-            // Remove the entry from the queue to keep it clean and improve
-            // performance.
-            .map(|pos| self.selectors.remove(pos))
+        if self.selectors.is_empty() {
+            None
+        } else {
+            let thread_id = current_thread_id();
+
+            self.selectors
+                .iter()
+                .position(|selector| {
+                    // Does the entry belong to a different thread?
+                    selector.cx.thread_id() != thread_id
+                        && selector // Try selecting this operation.
+                            .cx
+                            .try_select(Selected::Operation(selector.oper))
+                            .is_ok()
+                        && {
+                            // Provide the packet.
+                            selector.cx.store_packet(selector.packet);
+                            // Wake the thread up.
+                            selector.cx.unpark();
+                            true
+                        }
+                })
+                // Remove the entry from the queue to keep it clean and improve
+                // performance.
+                .map(|pos| self.selectors.remove(pos))
+        }
     }
 
     /// Notifies all operations waiting to be ready.
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 5f5f7ea25fb..fe932fd6bd3 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -1925,7 +1925,8 @@ impl Config {
                 .unwrap();
         if !(source_version == rustc_version
             || (source_version.major == rustc_version.major
-                && source_version.minor == rustc_version.minor + 1))
+                && (source_version.minor == rustc_version.minor
+                    || source_version.minor == rustc_version.minor + 1)))
         {
             let prev_version = format!("{}.{}.x", source_version.major, source_version.minor - 1);
             eprintln!(
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 4522819f996..b34a4b2dc63 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -1074,11 +1074,7 @@ impl Step for Cargo {
 
         tarball.add_file(&cargo, "bin", 0o755);
         tarball.add_file(etc.join("_cargo"), "share/zsh/site-functions", 0o644);
-        tarball.add_renamed_file(
-            etc.join("cargo.bashcomp.sh"),
-            "src/etc/bash_completion.d",
-            "cargo",
-        );
+        tarball.add_renamed_file(etc.join("cargo.bashcomp.sh"), "etc/bash_completion.d", "cargo");
         tarball.add_dir(etc.join("man"), "share/man/man1");
         tarball.add_legal_and_readme_to("share/doc/cargo");
 
diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
index cbcd11debfd..44e7cbfba08 100644
--- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
@@ -31,7 +31,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
     ("clippy::stutter", "clippy::module_name_repetitions"),
     ("clippy::to_string_in_display", "clippy::recursive_format_impl"),
     ("clippy::zero_width_space", "clippy::invisible_characters"),
-    ("clippy::cast_ref_to_mut", "cast_ref_to_mut"),
+    ("clippy::cast_ref_to_mut", "invalid_reference_casting"),
     ("clippy::clone_double_ref", "suspicious_double_ref_op"),
     ("clippy::cmp_nan", "invalid_nan_comparisons"),
     ("clippy::drop_bounds", "drop_bounds"),
diff --git a/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs b/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs
index 83db2a07d33..cc36ce5f487 100644
--- a/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs
+++ b/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs
@@ -1,4 +1,7 @@
 //@aux-build:proc_macro_attr.rs:proc-macro
+// Flaky test, see https://github.com/rust-lang/rust/issues/113585.
+//@ignore-32bit
+//@ignore-64bit
 #![warn(clippy::empty_line_after_doc_comments)]
 #![allow(clippy::assertions_on_constants)]
 #![feature(custom_inner_attributes)]
diff --git a/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs b/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs
index b2d7ddae427..bc54e0fd2de 100644
--- a/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs
+++ b/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs
@@ -1,4 +1,7 @@
 //@aux-build:proc_macro_attr.rs:proc-macro
+// Flaky test, see https://github.com/rust-lang/rust/issues/113585.
+//@ignore-32bit
+//@ignore-64bit
 #![warn(clippy::empty_line_after_outer_attr)]
 #![allow(clippy::assertions_on_constants)]
 #![feature(custom_inner_attributes)]
diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs b/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs
index 876f16a3854..321aa69a1a5 100644
--- a/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs
+++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs
@@ -1,4 +1,7 @@
 //@aux-build:proc_macro_attr.rs:proc-macro
+// Flaky test, see https://github.com/rust-lang/rust/issues/113585.
+//@ignore-32bit
+//@ignore-64bit
 
 #![warn(clippy::needless_arbitrary_self_type)]
 
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index b24c83d9a0d..cc2295ea507 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -28,9 +28,9 @@
 #![allow(clippy::module_name_repetitions)]
 #![allow(clippy::recursive_format_impl)]
 #![allow(clippy::invisible_characters)]
-#![allow(cast_ref_to_mut)]
 #![allow(suspicious_double_ref_op)]
 #![allow(invalid_nan_comparisons)]
+#![allow(invalid_reference_casting)]
 #![allow(drop_bounds)]
 #![allow(dropping_copy_types)]
 #![allow(dropping_references)]
@@ -78,7 +78,7 @@
 #![warn(clippy::module_name_repetitions)]
 #![warn(clippy::recursive_format_impl)]
 #![warn(clippy::invisible_characters)]
-#![warn(cast_ref_to_mut)]
+#![warn(invalid_reference_casting)]
 #![warn(suspicious_double_ref_op)]
 #![warn(invalid_nan_comparisons)]
 #![warn(drop_bounds)]
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index baa6345a64f..399335aff4e 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -28,9 +28,9 @@
 #![allow(clippy::module_name_repetitions)]
 #![allow(clippy::recursive_format_impl)]
 #![allow(clippy::invisible_characters)]
-#![allow(cast_ref_to_mut)]
 #![allow(suspicious_double_ref_op)]
 #![allow(invalid_nan_comparisons)]
+#![allow(invalid_reference_casting)]
 #![allow(drop_bounds)]
 #![allow(dropping_copy_types)]
 #![allow(dropping_references)]
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index ae25c3b46bd..079371330be 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -174,11 +174,11 @@ error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_ch
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
-error: lint `clippy::cast_ref_to_mut` has been renamed to `cast_ref_to_mut`
+error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting`
   --> $DIR/rename.rs:81:9
    |
 LL | #![warn(clippy::cast_ref_to_mut)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `cast_ref_to_mut`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting`
 
 error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
   --> $DIR/rename.rs:82:9
diff --git a/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.rs b/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.rs
index 1edd7748cde..0c7f4b89711 100644
--- a/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.rs
+++ b/src/tools/miri/tests/fail/both_borrows/shr_frozen_violation1.rs
@@ -1,7 +1,7 @@
 //@revisions: stack tree
 //@[tree]compile-flags: -Zmiri-tree-borrows
 
-#![allow(cast_ref_to_mut)]
+#![allow(invalid_reference_casting)]
 
 fn foo(x: &mut i32) -> i32 {
     *x = 5;
diff --git a/src/tools/miri/tests/fail/modifying_constants.rs b/src/tools/miri/tests/fail/modifying_constants.rs
index 40ba31dad8f..0d1bd7929b5 100644
--- a/src/tools/miri/tests/fail/modifying_constants.rs
+++ b/src/tools/miri/tests/fail/modifying_constants.rs
@@ -1,7 +1,7 @@
 // This should fail even without validation/SB
 //@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
 
-#![allow(cast_ref_to_mut)]
+#![allow(invalid_reference_casting)]
 
 fn main() {
     let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee
diff --git a/tests/ui/const-generics/issues/issue-100313.rs b/tests/ui/const-generics/issues/issue-100313.rs
index 9a9d4721c84..4e9d3626aa8 100644
--- a/tests/ui/const-generics/issues/issue-100313.rs
+++ b/tests/ui/const-generics/issues/issue-100313.rs
@@ -9,7 +9,6 @@ impl <const B: &'static bool> T<B> {
         unsafe {
             *(B as *const bool as *mut bool) = false;
             //~^ ERROR evaluation of constant value failed [E0080]
-            //~| ERROR casting `&T` to `&mut T` is undefined behavior
         }
     }
 }
diff --git a/tests/ui/const-generics/issues/issue-100313.stderr b/tests/ui/const-generics/issues/issue-100313.stderr
index ffc34a3a41e..d4b486376ca 100644
--- a/tests/ui/const-generics/issues/issue-100313.stderr
+++ b/tests/ui/const-generics/issues/issue-100313.stderr
@@ -1,11 +1,3 @@
-error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/issue-100313.rs:10:13
-   |
-LL |             *(B as *const bool as *mut bool) = false;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `#[deny(cast_ref_to_mut)]` on by default
-
 error[E0080]: evaluation of constant value failed
   --> $DIR/issue-100313.rs:10:13
    |
@@ -18,11 +10,11 @@ note: inside `T::<&true>::set_false`
 LL |             *(B as *const bool as *mut bool) = false;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: inside `_`
-  --> $DIR/issue-100313.rs:19:5
+  --> $DIR/issue-100313.rs:18:5
    |
 LL |     x.set_false();
    |     ^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/lint/lint-ctypes-113436-1.rs b/tests/ui/lint/lint-ctypes-113436-1.rs
new file mode 100644
index 00000000000..1ca59c6868d
--- /dev/null
+++ b/tests/ui/lint/lint-ctypes-113436-1.rs
@@ -0,0 +1,28 @@
+#![deny(improper_ctypes_definitions)]
+
+#[repr(C)]
+pub struct Foo {
+    a: u8,
+    b: (),
+}
+
+extern "C" fn foo(x: Foo) -> Foo {
+    todo!()
+}
+
+struct NotSafe(u32);
+
+#[repr(C)]
+pub struct Bar {
+    a: u8,
+    b: (),
+    c: NotSafe,
+}
+
+extern "C" fn bar(x: Bar) -> Bar {
+    //~^ ERROR `extern` fn uses type `NotSafe`, which is not FFI-safe
+    //~^^ ERROR `extern` fn uses type `NotSafe`, which is not FFI-safe
+    todo!()
+}
+
+fn main() {}
diff --git a/tests/ui/lint/lint-ctypes-113436-1.stderr b/tests/ui/lint/lint-ctypes-113436-1.stderr
new file mode 100644
index 00000000000..7b63043f057
--- /dev/null
+++ b/tests/ui/lint/lint-ctypes-113436-1.stderr
@@ -0,0 +1,35 @@
+error: `extern` fn uses type `NotSafe`, which is not FFI-safe
+  --> $DIR/lint-ctypes-113436-1.rs:22:22
+   |
+LL | extern "C" fn bar(x: Bar) -> Bar {
+   |                      ^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
+note: the type is defined here
+  --> $DIR/lint-ctypes-113436-1.rs:13:1
+   |
+LL | struct NotSafe(u32);
+   | ^^^^^^^^^^^^^^
+note: the lint level is defined here
+  --> $DIR/lint-ctypes-113436-1.rs:1:9
+   |
+LL | #![deny(improper_ctypes_definitions)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `extern` fn uses type `NotSafe`, which is not FFI-safe
+  --> $DIR/lint-ctypes-113436-1.rs:22:30
+   |
+LL | extern "C" fn bar(x: Bar) -> Bar {
+   |                              ^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
+note: the type is defined here
+  --> $DIR/lint-ctypes-113436-1.rs:13:1
+   |
+LL | struct NotSafe(u32);
+   | ^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/lint/lint-ctypes-113436.rs b/tests/ui/lint/lint-ctypes-113436.rs
new file mode 100644
index 00000000000..4f733b5bb16
--- /dev/null
+++ b/tests/ui/lint/lint-ctypes-113436.rs
@@ -0,0 +1,34 @@
+// check-pass
+#![deny(improper_ctypes_definitions)]
+
+#[repr(C)]
+pub struct Wrap<T>(T);
+
+#[repr(transparent)]
+pub struct TransparentWrap<T>(T);
+
+pub extern "C" fn f() -> Wrap<()> {
+    todo!()
+}
+
+const _: extern "C" fn() -> Wrap<()> = f;
+
+pub extern "C" fn ff() -> Wrap<Wrap<()>> {
+    todo!()
+}
+
+const _: extern "C" fn() -> Wrap<Wrap<()>> = ff;
+
+pub extern "C" fn g() -> TransparentWrap<()> {
+    todo!()
+}
+
+const _: extern "C" fn() -> TransparentWrap<()> = g;
+
+pub extern "C" fn gg() -> TransparentWrap<TransparentWrap<()>> {
+    todo!()
+}
+
+const _: extern "C" fn() -> TransparentWrap<TransparentWrap<()>> = gg;
+
+fn main() {}
diff --git a/tests/ui/lint/lint-ctypes-113900.rs b/tests/ui/lint/lint-ctypes-113900.rs
new file mode 100644
index 00000000000..ac4ff1ae2df
--- /dev/null
+++ b/tests/ui/lint/lint-ctypes-113900.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+// Extending `improper_ctypes` to check external-ABI fn-ptrs means that it can encounter
+// projections which cannot be normalized - unsurprisingly, this shouldn't crash the compiler.
+
+trait Bar {
+    type Assoc;
+}
+
+type Foo<T> = extern "C" fn() -> <T as Bar>::Assoc;
+
+fn main() {}
diff --git a/tests/ui/lint/cast_ref_to_mut.rs b/tests/ui/lint/reference_casting.rs
index 745d7070143..9963820499e 100644
--- a/tests/ui/lint/cast_ref_to_mut.rs
+++ b/tests/ui/lint/reference_casting.rs
@@ -1,6 +1,7 @@
 // check-fail
 
 #![feature(ptr_from_ref)]
+#![deny(invalid_reference_casting)]
 
 extern "C" {
     // N.B., mutability can be easily incorrect in FFI calls -- as
diff --git a/tests/ui/lint/cast_ref_to_mut.stderr b/tests/ui/lint/reference_casting.stderr
index baff00d6c04..d5b9bbef643 100644
--- a/tests/ui/lint/cast_ref_to_mut.stderr
+++ b/tests/ui/lint/reference_casting.stderr
@@ -1,61 +1,65 @@
 error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/cast_ref_to_mut.rs:19:9
+  --> $DIR/reference_casting.rs:20:9
    |
 LL |         (*(a as *const _ as *mut String)).push_str(" world");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `#[deny(cast_ref_to_mut)]` on by default
+note: the lint level is defined here
+  --> $DIR/reference_casting.rs:4:9
+   |
+LL | #![deny(invalid_reference_casting)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/cast_ref_to_mut.rs:21:9
+  --> $DIR/reference_casting.rs:22:9
    |
 LL |         *(a as *const _ as *mut _) = String::from("Replaced");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/cast_ref_to_mut.rs:23:9
+  --> $DIR/reference_casting.rs:24:9
    |
 LL |         *(a as *const _ as *mut String) += " world";
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/cast_ref_to_mut.rs:25:25
+  --> $DIR/reference_casting.rs:26:25
    |
 LL |         let _num = &mut *(num as *const i32 as *mut i32);
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/cast_ref_to_mut.rs:27:25
+  --> $DIR/reference_casting.rs:28:25
    |
 LL |         let _num = &mut *(num as *const i32).cast_mut();
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/cast_ref_to_mut.rs:29:20
+  --> $DIR/reference_casting.rs:30:20
    |
 LL |         let _num = *{ num as *const i32 }.cast_mut();
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/cast_ref_to_mut.rs:31:9
+  --> $DIR/reference_casting.rs:32:9
    |
 LL |         *std::ptr::from_ref(num).cast_mut() += 1;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/cast_ref_to_mut.rs:33:9
+  --> $DIR/reference_casting.rs:34:9
    |
 LL |         *std::ptr::from_ref({ num }).cast_mut() += 1;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/cast_ref_to_mut.rs:35:9
+  --> $DIR/reference_casting.rs:36:9
    |
 LL |         *{ std::ptr::from_ref(num) }.cast_mut() += 1;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-  --> $DIR/cast_ref_to_mut.rs:37:9
+  --> $DIR/reference_casting.rs:38:9
    |
 LL |         *(std::ptr::from_ref({ num }) as *mut i32) += 1;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/proc-macro/auxiliary/exports_no_mangle.rs b/tests/ui/proc-macro/auxiliary/exports_no_mangle.rs
new file mode 100644
index 00000000000..a8a478ffc74
--- /dev/null
+++ b/tests/ui/proc-macro/auxiliary/exports_no_mangle.rs
@@ -0,0 +1,11 @@
+// force-host
+// no-prefer-dynamic
+#![crate_type="lib"]
+
+// Issue 111888: this crate (1.) is imported by a proc-macro crate and (2.)
+// exports a no_mangle function; that combination of acts was broken for some
+// period of time. See further discussion in the test file that imports this
+// crate.
+
+#[no_mangle]
+pub fn some_no_mangle_function() { }
diff --git a/tests/ui/proc-macro/no-mangle-in-proc-macro-issue-111888.rs b/tests/ui/proc-macro/no-mangle-in-proc-macro-issue-111888.rs
new file mode 100644
index 00000000000..4e5208e5058
--- /dev/null
+++ b/tests/ui/proc-macro/no-mangle-in-proc-macro-issue-111888.rs
@@ -0,0 +1,22 @@
+// build-pass
+// force-host
+// no-prefer-dynamic
+// aux-build:exports_no_mangle.rs
+#![crate_type = "proc-macro"]
+
+// Issue #111888: this proc-macro crate imports another crate that itself
+// exports a no_mangle function.
+//
+// That combination was broken for a period of time, because:
+//
+// In PR #99944 we *stopped* exporting no_mangle symbols from
+// proc-macro crates. The constructed linker version script still referred
+// to them, but resolving that discrepancy was left as a FIXME in the code.
+//
+// In PR #108017 we started telling the linker to check (via the
+// `--no-undefined-version` linker invocation flag) that every symbol referenced
+// in the "linker version script" is actually present in the linker input. So
+// the unresolved discrepancy from #99944 started surfacing as a compile-time
+// error.
+
+extern crate exports_no_mangle;