about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-01-04 10:02:59 +0000
committerbors <bors@rust-lang.org>2025-01-04 10:02:59 +0000
commitf17cf744f5f757ef9dc5f45508332c75d74ffad0 (patch)
tree593de0aea8c1d1db9cbc41c9f69e0aac80a2a172
parent49761b073c2ca81a3e687183cf2e171cdfd61668 (diff)
parent75e412b8d10591bca72c0bdba124e8a4ca732dae (diff)
downloadrust-f17cf744f5f757ef9dc5f45508332c75d74ffad0.tar.gz
rust-f17cf744f5f757ef9dc5f45508332c75d74ffad0.zip
Auto merge of #135095 - matthiaskrgr:rollup-tmgxckq, r=matthiaskrgr
Rollup of 7 pull requests

Successful merges:

 - #133964 (core: implement `bool::select_unpredictable`)
 - #135001 (Allow using self-contained LLD in bootstrap)
 - #135055 (Report impl method has stricter requirements even when RPITIT inference gets in the way)
 - #135064 (const-in-pattern: test that the PartialEq impl does not need to be const)
 - #135066 (bootstrap: support `./x check run-make-support`)
 - #135069 (remove unused function params)
 - #135084 (Update carrying_mul_add test to tolerate `nuw`)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs20
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs4
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs28
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs7
-rw-r--r--library/core/src/bool.rs48
-rw-r--r--library/core/src/intrinsics/mod.rs2
-rw-r--r--library/core/src/slice/mod.rs4
-rw-r--r--src/bootstrap/src/core/build_steps/check.rs5
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs1
-rw-r--r--src/bootstrap/src/core/builder/mod.rs1
-rw-r--r--src/bootstrap/src/utils/helpers.rs15
-rw-r--r--tests/codegen/bool-select-unpredictable.rs35
-rw-r--r--tests/codegen/intrinsics/carrying_mul_add.rs4
-rw-r--r--tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs2
-rw-r--r--tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.stderr23
-rw-r--r--tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr22
-rw-r--r--tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs4
-rw-r--r--tests/ui/impl-trait/in-trait/mismatched-where-clauses.rs12
-rw-r--r--tests/ui/impl-trait/in-trait/mismatched-where-clauses.stderr12
-rw-r--r--tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr24
-rw-r--r--tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.rs2
-rw-r--r--tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.stderr21
-rw-r--r--tests/ui/traits/const-traits/pattern-custom-partial-eq.rs54
25 files changed, 270 insertions, 86 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index a6b504de3da..4a957d5da24 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -529,6 +529,26 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
     let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new_with_diagnostics(infcx);
 
+    // Check that the where clauses of the impl are satisfied by the hybrid param env.
+    // You might ask -- what does this have to do with RPITIT inference? Nothing.
+    // We check these because if the where clauses of the signatures do not match
+    // up, then we don't want to give spurious other errors that point at the RPITITs.
+    // They're not necessary to check, though, because we already check them in
+    // `compare_method_predicate_entailment`.
+    let impl_m_own_bounds = tcx.predicates_of(impl_m_def_id).instantiate_own_identity();
+    for (predicate, span) in impl_m_own_bounds {
+        let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id);
+        let predicate = ocx.normalize(&normalize_cause, param_env, predicate);
+
+        let cause =
+            ObligationCause::new(span, impl_m_def_id, ObligationCauseCode::CompareImplItem {
+                impl_item_def_id: impl_m_def_id,
+                trait_item_def_id: trait_m.def_id,
+                kind: impl_m.kind,
+            });
+        ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
+    }
+
     // Normalize the impl signature with fresh variables for lifetime inference.
     let misc_cause = ObligationCause::misc(return_span, impl_m_def_id);
     let impl_sig = ocx.normalize(
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 406e732744b..77745599afb 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -69,10 +69,10 @@ impl<'tcx> Ty<'tcx> {
     /// description in error messages. This is used in the primary span label. Beyond what
     /// `is_simple_ty` includes, it also accepts ADTs with no type arguments and references to
     /// ADTs with no type arguments.
-    pub fn is_simple_text(self, tcx: TyCtxt<'tcx>) -> bool {
+    pub fn is_simple_text(self) -> bool {
         match self.kind() {
             Adt(_, args) => args.non_erasable_generics().next().is_none(),
-            Ref(_, ty, _) => ty.is_simple_text(tcx),
+            Ref(_, ty, _) => ty.is_simple_text(),
             _ => self.is_simple_ty(),
         }
     }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index aed00aecefc..2b3c98db966 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -491,6 +491,10 @@ fn type_has_partial_eq_impl<'tcx>(
     // `PartialEq` for some lifetime but *not* for `'static`? If this ever becomes a problem
     // we'll need to leave some sort of trace of this requirement in the MIR so that borrowck
     // can ensure that the type really implements `PartialEq`.
+    // We also do *not* require `const PartialEq`, not even in `const fn`. This violates the model
+    // that patterns can only do things that the code could also do without patterns, but it is
+    // needed for backwards compatibility. The actual pattern matching compares primitive values,
+    // `PartialEq::eq` never gets invoked, so there's no risk of us running non-const code.
     (
         infcx.predicate_must_hold_modulo_regions(&partial_eq_obligation),
         automatically_derived,
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index a3320f99cc3..f6536d78761 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -1822,9 +1822,6 @@ impl<'tcx> Visitor<'tcx> for EnsureCoroutineFieldAssignmentsNeverAlias<'_> {
 fn check_suspend_tys<'tcx>(tcx: TyCtxt<'tcx>, layout: &CoroutineLayout<'tcx>, body: &Body<'tcx>) {
     let mut linted_tys = FxHashSet::default();
 
-    // We want a user-facing param-env.
-    let param_env = tcx.param_env(body.source.def_id());
-
     for (variant, yield_source_info) in
         layout.variant_fields.iter().zip(&layout.variant_source_info)
     {
@@ -1838,7 +1835,7 @@ fn check_suspend_tys<'tcx>(tcx: TyCtxt<'tcx>, layout: &CoroutineLayout<'tcx>, bo
                     continue;
                 };
 
-                check_must_not_suspend_ty(tcx, decl.ty, hir_id, param_env, SuspendCheckData {
+                check_must_not_suspend_ty(tcx, decl.ty, hir_id, SuspendCheckData {
                     source_span: decl.source_info.span,
                     yield_span: yield_source_info.span,
                     plural_len: 1,
@@ -1868,7 +1865,6 @@ fn check_must_not_suspend_ty<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
     hir_id: hir::HirId,
-    param_env: ty::ParamEnv<'tcx>,
     data: SuspendCheckData<'_>,
 ) -> bool {
     if ty.is_unit() {
@@ -1883,16 +1879,13 @@ fn check_must_not_suspend_ty<'tcx>(
         ty::Adt(_, args) if ty.is_box() => {
             let boxed_ty = args.type_at(0);
             let allocator_ty = args.type_at(1);
-            check_must_not_suspend_ty(tcx, boxed_ty, hir_id, param_env, SuspendCheckData {
+            check_must_not_suspend_ty(tcx, boxed_ty, hir_id, SuspendCheckData {
                 descr_pre: &format!("{}boxed ", data.descr_pre),
                 ..data
-            }) || check_must_not_suspend_ty(
-                tcx,
-                allocator_ty,
-                hir_id,
-                param_env,
-                SuspendCheckData { descr_pre: &format!("{}allocator ", data.descr_pre), ..data },
-            )
+            }) || check_must_not_suspend_ty(tcx, allocator_ty, hir_id, SuspendCheckData {
+                descr_pre: &format!("{}allocator ", data.descr_pre),
+                ..data
+            })
         }
         ty::Adt(def, _) => check_must_not_suspend_def(tcx, def.did(), hir_id, data),
         // FIXME: support adding the attribute to TAITs
@@ -1937,7 +1930,7 @@ fn check_must_not_suspend_ty<'tcx>(
             let mut has_emitted = false;
             for (i, ty) in fields.iter().enumerate() {
                 let descr_post = &format!(" in tuple element {i}");
-                if check_must_not_suspend_ty(tcx, ty, hir_id, param_env, SuspendCheckData {
+                if check_must_not_suspend_ty(tcx, ty, hir_id, SuspendCheckData {
                     descr_post,
                     ..data
                 }) {
@@ -1948,7 +1941,7 @@ fn check_must_not_suspend_ty<'tcx>(
         }
         ty::Array(ty, len) => {
             let descr_pre = &format!("{}array{} of ", data.descr_pre, plural_suffix);
-            check_must_not_suspend_ty(tcx, ty, hir_id, param_env, SuspendCheckData {
+            check_must_not_suspend_ty(tcx, ty, hir_id, SuspendCheckData {
                 descr_pre,
                 // FIXME(must_not_suspend): This is wrong. We should handle printing unevaluated consts.
                 plural_len: len.try_to_target_usize(tcx).unwrap_or(0) as usize + 1,
@@ -1959,10 +1952,7 @@ fn check_must_not_suspend_ty<'tcx>(
         // may not be considered live across the await point.
         ty::Ref(_region, ty, _mutability) => {
             let descr_pre = &format!("{}reference{} to ", data.descr_pre, plural_suffix);
-            check_must_not_suspend_ty(tcx, ty, hir_id, param_env, SuspendCheckData {
-                descr_pre,
-                ..data
-            })
+            check_must_not_suspend_ty(tcx, ty, hir_id, SuspendCheckData { descr_pre, ..data })
         }
         _ => false,
     }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index ee5ce19cb4d..d89470dabec 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -1496,8 +1496,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     ValuePairs::Terms(ExpectedFound { expected, found }) => {
                         match (expected.unpack(), found.unpack()) {
                             (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => {
-                                let is_simple_err = expected.is_simple_text(self.tcx)
-                                    && found.is_simple_text(self.tcx);
+                                let is_simple_err =
+                                    expected.is_simple_text() && found.is_simple_text();
                                 OpaqueTypesVisitor::visit_expected_found(
                                     self.tcx, expected, found, span,
                                 )
@@ -1736,8 +1736,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         (true, _) => format!(" ({})", ty.sort_string(self.tcx)),
                         (false, _) => "".to_string(),
                     };
-                    if !(values.expected.is_simple_text(self.tcx)
-                        && values.found.is_simple_text(self.tcx))
+                    if !(values.expected.is_simple_text() && values.found.is_simple_text())
                         || (exp_found.is_some_and(|ef| {
                             // This happens when the type error is a subset of the expectation,
                             // like when you have two references but one is `usize` and the other
diff --git a/library/core/src/bool.rs b/library/core/src/bool.rs
index 1590b9f29fc..3c589ca5dfa 100644
--- a/library/core/src/bool.rs
+++ b/library/core/src/bool.rs
@@ -61,4 +61,52 @@ impl bool {
     pub fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
         if self { Some(f()) } else { None }
     }
+
+    /// Returns either `true_val` or `false_val` depending on the value of
+    /// `self`, with a hint to the compiler that `self` is unlikely
+    /// to be correctly predicted by a CPU’s branch predictor.
+    ///
+    /// This method is functionally equivalent to
+    /// ```ignore (this is just for illustrative purposes)
+    /// fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T {
+    ///     if b { true_val } else { false_val }
+    /// }
+    /// ```
+    /// but might generate different assembly. In particular, on platforms with
+    /// a conditional move or select instruction (like `cmov` on x86 or `csel`
+    /// on ARM) the optimizer might use these instructions to avoid branches,
+    /// which can benefit performance if the branch predictor is struggling
+    /// with predicting `condition`, such as in an implementation of  binary
+    /// search.
+    ///
+    /// Note however that this lowering is not guaranteed (on any platform) and
+    /// should not be relied upon when trying to write constant-time code. Also
+    /// be aware that this lowering might *decrease* performance if `condition`
+    /// is well-predictable. It is advisable to perform benchmarks to tell if
+    /// this function is useful.
+    ///
+    /// # Examples
+    ///
+    /// Distribute values evenly between two buckets:
+    /// ```
+    /// #![feature(select_unpredictable)]
+    ///
+    /// use std::hash::BuildHasher;
+    ///
+    /// fn append<H: BuildHasher>(hasher: &H, v: i32, bucket_one: &mut Vec<i32>, bucket_two: &mut Vec<i32>) {
+    ///     let hash = hasher.hash_one(&v);
+    ///     let bucket = (hash % 2 == 0).select_unpredictable(bucket_one, bucket_two);
+    ///     bucket.push(v);
+    /// }
+    /// # let hasher = std::collections::hash_map::RandomState::new();
+    /// # let mut bucket_one = Vec::new();
+    /// # let mut bucket_two = Vec::new();
+    /// # append(&hasher, 42, &mut bucket_one, &mut bucket_two);
+    /// # assert_eq!(bucket_one.len() + bucket_two.len(), 1);
+    /// ```
+    #[inline(always)]
+    #[unstable(feature = "select_unpredictable", issue = "133962")]
+    pub fn select_unpredictable<T>(self, true_val: T, false_val: T) -> T {
+        crate::intrinsics::select_unpredictable(self, true_val, false_val)
+    }
 }
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index b5c31d82467..7d44ea7a66b 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -1545,7 +1545,7 @@ pub const fn unlikely(b: bool) -> bool {
 /// Therefore, implementations must not require the user to uphold
 /// any safety invariants.
 ///
-/// This intrinsic does not have a stable counterpart.
+/// The public form of this instrinsic is [`bool::select_unpredictable`].
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic]
 #[rustc_nounwind]
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index df9720698d3..073cca7daef 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -7,7 +7,7 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use crate::cmp::Ordering::{self, Equal, Greater, Less};
-use crate::intrinsics::{exact_div, select_unpredictable, unchecked_sub};
+use crate::intrinsics::{exact_div, unchecked_sub};
 use crate::mem::{self, SizedTypeProperties};
 use crate::num::NonZero;
 use crate::ops::{Bound, OneSidedRange, Range, RangeBounds, RangeInclusive};
@@ -2835,7 +2835,7 @@ impl<T> [T] {
             // Binary search interacts poorly with branch prediction, so force
             // the compiler to use conditional moves if supported by the target
             // architecture.
-            base = select_unpredictable(cmp == Greater, base, mid);
+            base = (cmp == Greater).select_unpredictable(base, mid);
 
             // This is imprecise in the case where `size` is odd and the
             // comparison returns Greater: the mid element still gets included
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index 9434d876df8..7fd811ac507 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -491,6 +491,11 @@ tool_check_step!(MiroptTestTools { path: "src/tools/miropt-test-tools" });
 tool_check_step!(TestFloatParse { path: "src/etc/test-float-parse" });
 
 tool_check_step!(Bootstrap { path: "src/bootstrap", default: false });
+
+// `run-make-support` will be built as part of suitable run-make compiletest test steps, but support
+// check to make it easier to work on.
+tool_check_step!(RunMakeSupport { path: "src/tools/run-make-support", default: false });
+
 // Compiletest is implicitly "checked" when it gets built in order to run tests,
 // so this is mainly for people working on compiletest to run locally.
 tool_check_step!(Compiletest { path: "src/tools/compiletest", default: false });
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 84d09bbc2e0..64bcb0b85f4 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -1893,7 +1893,6 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
 
         let mut targetflags = flags;
         targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display()));
-        targetflags.extend(linker_flags(builder, compiler.host, LldThreads::No));
         for flag in targetflags {
             cmd.arg("--target-rustcflags").arg(flag);
         }
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index 04d51fab5d5..db2c4744eb0 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -935,6 +935,7 @@ impl<'a> Builder<'a> {
                 check::RustAnalyzer,
                 check::TestFloatParse,
                 check::Bootstrap,
+                check::RunMakeSupport,
                 check::Compiletest,
             ),
             Kind::Test => describe!(
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index 985d733a41f..2ff99e7e499 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -481,7 +481,20 @@ pub fn linker_flags(
 ) -> Vec<String> {
     let mut args = vec![];
     if !builder.is_lld_direct_linker(target) && builder.config.lld_mode.is_used() {
-        args.push(String::from("-Clink-arg=-fuse-ld=lld"));
+        match builder.config.lld_mode {
+            LldMode::External => {
+                args.push("-Clinker-flavor=gnu-lld-cc".to_string());
+                // FIXME(kobzol): remove this flag once MCP510 gets stabilized
+                args.push("-Zunstable-options".to_string());
+            }
+            LldMode::SelfContained => {
+                args.push("-Clinker-flavor=gnu-lld-cc".to_string());
+                args.push("-Clink-self-contained=+linker".to_string());
+                // FIXME(kobzol): remove this flag once MCP510 gets stabilized
+                args.push("-Zunstable-options".to_string());
+            }
+            LldMode::Unused => unreachable!(),
+        };
 
         if matches!(lld_threads, LldThreads::No) {
             args.push(format!(
diff --git a/tests/codegen/bool-select-unpredictable.rs b/tests/codegen/bool-select-unpredictable.rs
new file mode 100644
index 00000000000..1562b177542
--- /dev/null
+++ b/tests/codegen/bool-select-unpredictable.rs
@@ -0,0 +1,35 @@
+//@ compile-flags: -O
+
+#![feature(select_unpredictable)]
+#![crate_type = "lib"]
+
+#[no_mangle]
+pub fn test_int(p: bool, a: u64, b: u64) -> u64 {
+    // CHECK-LABEL: define{{.*}} @test_int
+    // CHECK: select i1 %p, i64 %a, i64 %b, !unpredictable
+    p.select_unpredictable(a, b)
+}
+
+#[no_mangle]
+pub fn test_pair(p: bool, a: (u64, u64), b: (u64, u64)) -> (u64, u64) {
+    // CHECK-LABEL: define{{.*}} @test_pair
+    // CHECK: select i1 %p, {{.*}}, !unpredictable
+    p.select_unpredictable(a, b)
+}
+
+struct Large {
+    e: [u64; 100],
+}
+
+#[no_mangle]
+pub fn test_struct(p: bool, a: Large, b: Large) -> Large {
+    // CHECK-LABEL: define{{.*}} @test_struct
+    // CHECK: select i1 %p, {{.*}}, !unpredictable
+    p.select_unpredictable(a, b)
+}
+
+#[no_mangle]
+pub fn test_zst(p: bool, a: (), b: ()) -> () {
+    // CHECK-LABEL: define{{.*}} @test_zst
+    p.select_unpredictable(a, b)
+}
diff --git a/tests/codegen/intrinsics/carrying_mul_add.rs b/tests/codegen/intrinsics/carrying_mul_add.rs
index 174c4077f09..b53585a8a6e 100644
--- a/tests/codegen/intrinsics/carrying_mul_add.rs
+++ b/tests/codegen/intrinsics/carrying_mul_add.rs
@@ -84,7 +84,7 @@ pub unsafe fn cma_u128(a: u128, b: u128, c: u128, d: u128) -> (u128, u128) {
     // RAW: [[PAIR0:%.+]] = insertvalue { i128, i128 } poison, i128 [[LOW]], 0
     // RAW: [[PAIR1:%.+]] = insertvalue { i128, i128 } [[PAIR0]], i128 [[HIGH]], 1
     // OPT: store i128 [[LOW]], ptr %_0
-    // OPT: [[P1:%.+]] = getelementptr inbounds i8, ptr %_0, {{i32|i64}} 16
+    // OPT: [[P1:%.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %_0, {{i32|i64}} 16
     // OPT: store i128 [[HIGH]], ptr [[P1]]
     // CHECK: ret void
     carrying_mul_add(a, b, c, d)
@@ -111,7 +111,7 @@ pub unsafe fn cma_i128(a: i128, b: i128, c: i128, d: i128) -> (u128, i128) {
     // RAW: [[PAIR0:%.+]] = insertvalue { i128, i128 } poison, i128 [[LOW]], 0
     // RAW: [[PAIR1:%.+]] = insertvalue { i128, i128 } [[PAIR0]], i128 [[HIGH]], 1
     // OPT: store i128 [[LOW]], ptr %_0
-    // OPT: [[P1:%.+]] = getelementptr inbounds i8, ptr %_0, {{i32|i64}} 16
+    // OPT: [[P1:%.+]] = getelementptr inbounds{{( nuw)?}} i8, ptr %_0, {{i32|i64}} 16
     // OPT: store i128 [[HIGH]], ptr [[P1]]
     // CHECK: ret void
     carrying_mul_add(a, b, c, d)
diff --git a/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs b/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs
index b4df58b3c25..4dfeab9e8c3 100644
--- a/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs
+++ b/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs
@@ -11,9 +11,9 @@ struct Baz {}
 
 impl Foo for Baz {
     async fn bar<F>(&mut self, _func: F) -> ()
-    //~^ ERROR `F` cannot be sent between threads safely
     where
         F: FnMut() + Send,
+        //~^ impl has stricter requirements than trait
     {
         ()
     }
diff --git a/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.stderr b/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.stderr
index e6379954776..8d5cad4493e 100644
--- a/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.stderr
+++ b/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.stderr
@@ -1,21 +1,14 @@
-error[E0277]: `F` cannot be sent between threads safely
-  --> $DIR/remove-invalid-type-bound-suggest-issue-127555.rs:13:5
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/remove-invalid-type-bound-suggest-issue-127555.rs:15:22
    |
-LL | /     async fn bar<F>(&mut self, _func: F) -> ()
-LL | |
+LL | /     fn bar<F>(&mut self, func: F) -> impl std::future::Future<Output = ()> + Send
 LL | |     where
-LL | |         F: FnMut() + Send,
-   | |__________________________^ `F` cannot be sent between threads safely
-   |
-note: required by a bound in `<Baz as Foo>::bar`
-  --> $DIR/remove-invalid-type-bound-suggest-issue-127555.rs:16:22
-   |
-LL |     async fn bar<F>(&mut self, _func: F) -> ()
-   |              --- required by a bound in this associated function
+LL | |         F: FnMut();
+   | |___________________- definition of `bar` from trait
 ...
-LL |         F: FnMut() + Send,
-   |                      ^^^^ required by this bound in `<Baz as Foo>::bar`
+LL |           F: FnMut() + Send,
+   |                        ^^^^ impl has extra requirement `F: Send`
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0276`.
diff --git a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr
index e38e18857ef..b6e7e02f331 100644
--- a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr
+++ b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr
@@ -19,11 +19,11 @@ help: consider further restricting type parameter `F` with trait `MyFn`
 LL |         F: Callback<Self::CallbackArg> + MyFn<i32>,
    |                                        +++++++++++
 
-error[E0277]: the trait bound `F: MyFn<i32>` is not satisfied
-  --> $DIR/false-positive-predicate-entailment-error.rs:36:30
+error[E0277]: the trait bound `F: Callback<i32>` is not satisfied
+  --> $DIR/false-positive-predicate-entailment-error.rs:42:12
    |
-LL |     fn autobatch<F>(self) -> impl Trait
-   |                              ^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F`
+LL |         F: Callback<Self::CallbackArg>,
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F`
    |
 note: required for `F` to implement `Callback<i32>`
   --> $DIR/false-positive-predicate-entailment-error.rs:14:21
@@ -32,14 +32,14 @@ LL | impl<A, F: MyFn<A>> Callback<A> for F {
    |            -------  ^^^^^^^^^^^     ^
    |            |
    |            unsatisfied trait bound introduced here
-note: required by a bound in `<Sender as ChannelSender>::autobatch`
-  --> $DIR/false-positive-predicate-entailment-error.rs:43:12
+note: the requirement `F: Callback<i32>` appears on the `impl`'s method `autobatch` but not on the corresponding trait's method
+  --> $DIR/false-positive-predicate-entailment-error.rs:25:8
    |
-LL |     fn autobatch<F>(self) -> impl Trait
-   |        --------- required by a bound in this associated function
+LL | trait ChannelSender {
+   |       ------------- in this trait
 ...
-LL |         F: Callback<Self::CallbackArg>,
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<Sender as ChannelSender>::autobatch`
+LL |     fn autobatch<F>(self) -> impl Trait
+   |        ^^^^^^^^^ this trait's method doesn't have the requirement `F: Callback<i32>`
 help: consider further restricting type parameter `F` with trait `MyFn`
    |
 LL |         F: Callback<Self::CallbackArg> + MyFn<i32>,
@@ -118,7 +118,7 @@ LL |         F: Callback<Self::CallbackArg> + MyFn<i32>,
    |                                        +++++++++++
 
 error[E0277]: the trait bound `F: MyFn<i32>` is not satisfied
-  --> $DIR/false-positive-predicate-entailment-error.rs:43:12
+  --> $DIR/false-positive-predicate-entailment-error.rs:42:12
    |
 LL |         F: Callback<Self::CallbackArg>,
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F`
diff --git a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs
index 2987d183e04..cbe6c32b890 100644
--- a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs
+++ b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs
@@ -38,11 +38,11 @@ impl ChannelSender for Sender {
     //[current]~| ERROR the trait bound `F: MyFn<i32>` is not satisfied
     //[current]~| ERROR the trait bound `F: MyFn<i32>` is not satisfied
     //[current]~| ERROR the trait bound `F: MyFn<i32>` is not satisfied
-    //[current]~| ERROR the trait bound `F: MyFn<i32>` is not satisfied
     where
         F: Callback<Self::CallbackArg>,
         //[current]~^ ERROR the trait bound `F: MyFn<i32>` is not satisfied
-    {
+        //[current]~| ERROR the trait bound `F: Callback<i32>` is not satisfied
+        {
         Thing
     }
 }
diff --git a/tests/ui/impl-trait/in-trait/mismatched-where-clauses.rs b/tests/ui/impl-trait/in-trait/mismatched-where-clauses.rs
new file mode 100644
index 00000000000..a2c735cc126
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/mismatched-where-clauses.rs
@@ -0,0 +1,12 @@
+trait Foo {
+    fn foo<S>(s: S) -> impl Sized;
+}
+
+trait Bar {}
+
+impl Foo for () {
+    fn foo<S>(s: S) -> impl Sized where S: Bar {}
+    //~^ ERROR impl has stricter requirements than trait
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/mismatched-where-clauses.stderr b/tests/ui/impl-trait/in-trait/mismatched-where-clauses.stderr
new file mode 100644
index 00000000000..cc6e027cad7
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/mismatched-where-clauses.stderr
@@ -0,0 +1,12 @@
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/mismatched-where-clauses.rs:8:44
+   |
+LL |     fn foo<S>(s: S) -> impl Sized;
+   |     ------------------------------ definition of `foo` from trait
+...
+LL |     fn foo<S>(s: S) -> impl Sized where S: Bar {}
+   |                                            ^^^ impl has extra requirement `S: Bar`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0276`.
diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs
index ee47de2c732..ff265e576b9 100644
--- a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs
+++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs
@@ -8,7 +8,7 @@ impl Foo<char> for Bar {
     fn foo<F2: Foo<u8>>(self) -> impl Foo<u8> {
         //~^ ERROR: the trait bound `impl Foo<u8>: Foo<char>` is not satisfied [E0277]
         //~| ERROR: the trait bound `Bar: Foo<u8>` is not satisfied [E0277]
-        //~| ERROR: the trait bound `F2: Foo<u8>` is not satisfied
+        //~| ERROR: impl has stricter requirements than trait
         self
     }
 }
diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr
index 663c9a7f2ae..5cb80386b35 100644
--- a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr
+++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr
@@ -1,3 +1,12 @@
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/return-dont-satisfy-bounds.rs:8:16
+   |
+LL |     fn foo<F2>(self) -> impl Foo<T>;
+   |     -------------------------------- definition of `foo` from trait
+...
+LL |     fn foo<F2: Foo<u8>>(self) -> impl Foo<u8> {
+   |                ^^^^^^^ impl has extra requirement `F2: Foo<u8>`
+
 error[E0277]: the trait bound `impl Foo<u8>: Foo<char>` is not satisfied
   --> $DIR/return-dont-satisfy-bounds.rs:8:34
    |
@@ -11,18 +20,6 @@ note: required by a bound in `Foo::{synthetic#0}`
 LL |     fn foo<F2>(self) -> impl Foo<T>;
    |                              ^^^^^^ required by this bound in `Foo::{synthetic#0}`
 
-error[E0277]: the trait bound `F2: Foo<u8>` is not satisfied
-  --> $DIR/return-dont-satisfy-bounds.rs:8:34
-   |
-LL |     fn foo<F2: Foo<u8>>(self) -> impl Foo<u8> {
-   |                                  ^^^^^^^^^^^^ the trait `Foo<u8>` is not implemented for `F2`
-   |
-note: required by a bound in `<Bar as Foo<char>>::foo`
-  --> $DIR/return-dont-satisfy-bounds.rs:8:16
-   |
-LL |     fn foo<F2: Foo<u8>>(self) -> impl Foo<u8> {
-   |                ^^^^^^^ required by this bound in `<Bar as Foo<char>>::foo`
-
 error[E0277]: the trait bound `Bar: Foo<u8>` is not satisfied
   --> $DIR/return-dont-satisfy-bounds.rs:8:34
    |
@@ -38,4 +35,5 @@ LL |         self
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0276, E0277.
+For more information about an error, try `rustc --explain E0276`.
diff --git a/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.rs b/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.rs
index 37b0b229776..7a3a59d37c6 100644
--- a/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.rs
+++ b/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.rs
@@ -4,9 +4,9 @@ trait Extend {
 
 impl Extend for () {
     fn extend<'a: 'a>(s: &'a str) -> (Option<&'static &'a ()>, &'static str)
-    //~^ ERROR in type `&'static &'a ()`, reference has a longer lifetime than the data it references
     where
         'a: 'static,
+        //~^ impl has stricter requirements than trait
     {
         (None, s)
     }
diff --git a/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.stderr b/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.stderr
index 5ace64b6903..15bef5c78b0 100644
--- a/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.stderr
+++ b/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.stderr
@@ -1,16 +1,17 @@
-error[E0491]: in type `&'static &'a ()`, reference has a longer lifetime than the data it references
-  --> $DIR/rpitit-hidden-types-self-implied-wf-via-param.rs:6:38
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/rpitit-hidden-types-self-implied-wf-via-param.rs:8:13
    |
-LL |     fn extend<'a: 'a>(s: &'a str) -> (Option<&'static &'a ()>, &'static str)
-   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     fn extend<'a: 'a>(_: &'a str) -> (impl Sized + 'a, &'static str);
+   |     ----------------------------------------------------------------- definition of `extend` from trait
+...
+LL |         'a: 'static,
+   |             ^^^^^^^ impl has extra requirement `'a: 'static`
    |
-   = note: the pointer is valid for the static lifetime
-note: but the referenced data is only valid for the lifetime `'a` as defined here
-  --> $DIR/rpitit-hidden-types-self-implied-wf-via-param.rs:6:15
+help: copy the `where` clause predicates from the trait
+   |
+LL |     where 'a: 'a
    |
-LL |     fn extend<'a: 'a>(s: &'a str) -> (Option<&'static &'a ()>, &'static str)
-   |               ^^
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0491`.
+For more information about this error, try `rustc --explain E0276`.
diff --git a/tests/ui/traits/const-traits/pattern-custom-partial-eq.rs b/tests/ui/traits/const-traits/pattern-custom-partial-eq.rs
new file mode 100644
index 00000000000..1003775be2f
--- /dev/null
+++ b/tests/ui/traits/const-traits/pattern-custom-partial-eq.rs
@@ -0,0 +1,54 @@
+//! Ensure that a `const fn` can match on constants of a type that is `PartialEq`
+//! but not `const PartialEq`. This is accepted for backwards compatibility reasons.
+//@ check-pass
+#![feature(const_trait_impl)]
+
+#[derive(Eq, PartialEq)]
+pub struct Y(u8);
+pub const GREEN: Y = Y(4);
+pub const fn is_green(x: Y) -> bool {
+    match x { GREEN => true, _ => false }
+}
+
+struct CustomEq;
+
+impl Eq for CustomEq {}
+impl PartialEq for CustomEq {
+    fn eq(&self, _: &Self) -> bool {
+        false
+    }
+}
+
+#[derive(PartialEq, Eq)]
+#[allow(unused)]
+enum Foo {
+    Bar,
+    Baz,
+    Qux(CustomEq),
+}
+
+const BAR_BAZ: Foo = if 42 == 42 {
+    Foo::Bar
+} else {
+    Foo::Qux(CustomEq) // dead arm
+};
+
+const EMPTY: &[CustomEq] = &[];
+
+const fn test() {
+    // BAR_BAZ itself is fine but the enum has other variants
+    // that are non-structural. Still, this should be accepted.
+    match Foo::Qux(CustomEq) {
+        BAR_BAZ => panic!(),
+        _ => {}
+    }
+
+    // Similarly, an empty slice of a type that is non-structural
+    // is accepted.
+    match &[CustomEq] as &[CustomEq] {
+        EMPTY => panic!(),
+        _ => {},
+    }
+}
+
+fn main() {}