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>(self, f: F) -> Option { 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(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(hasher: &H, v: i32, bucket_one: &mut Vec, bucket_two: &mut Vec) { + /// 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(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] { // 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 { 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(&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(&mut self, _func: F) -> () -LL | | +LL | / fn bar(&mut self, func: F) -> impl std::future::Future + Send LL | | where -LL | | F: FnMut() + Send, - | |__________________________^ `F` cannot be sent between threads safely - | -note: required by a bound in `::bar` - --> $DIR/remove-invalid-type-bound-suggest-issue-127555.rs:16:22 - | -LL | async fn bar(&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 `::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 + MyFn, | +++++++++++ -error[E0277]: the trait bound `F: MyFn` is not satisfied - --> $DIR/false-positive-predicate-entailment-error.rs:36:30 +error[E0277]: the trait bound `F: Callback` is not satisfied + --> $DIR/false-positive-predicate-entailment-error.rs:42:12 | -LL | fn autobatch(self) -> impl Trait - | ^^^^^^^^^^ the trait `MyFn` is not implemented for `F` +LL | F: Callback, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyFn` is not implemented for `F` | note: required for `F` to implement `Callback` --> $DIR/false-positive-predicate-entailment-error.rs:14:21 @@ -32,14 +32,14 @@ LL | impl> Callback for F { | ------- ^^^^^^^^^^^ ^ | | | unsatisfied trait bound introduced here -note: required by a bound in `::autobatch` - --> $DIR/false-positive-predicate-entailment-error.rs:43:12 +note: the requirement `F: Callback` 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(self) -> impl Trait - | --------- required by a bound in this associated function +LL | trait ChannelSender { + | ------------- in this trait ... -LL | F: Callback, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `::autobatch` +LL | fn autobatch(self) -> impl Trait + | ^^^^^^^^^ this trait's method doesn't have the requirement `F: Callback` help: consider further restricting type parameter `F` with trait `MyFn` | LL | F: Callback + MyFn, @@ -118,7 +118,7 @@ LL | F: Callback + MyFn, | +++++++++++ error[E0277]: the trait bound `F: MyFn` is not satisfied - --> $DIR/false-positive-predicate-entailment-error.rs:43:12 + --> $DIR/false-positive-predicate-entailment-error.rs:42:12 | LL | F: Callback, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyFn` 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` is not satisfied //[current]~| ERROR the trait bound `F: MyFn` is not satisfied //[current]~| ERROR the trait bound `F: MyFn` is not satisfied - //[current]~| ERROR the trait bound `F: MyFn` is not satisfied where F: Callback, //[current]~^ ERROR the trait bound `F: MyFn` is not satisfied - { + //[current]~| ERROR the trait bound `F: Callback` 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) -> impl Sized; +} + +trait Bar {} + +impl Foo for () { + fn foo(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) -> impl Sized; + | ------------------------------ definition of `foo` from trait +... +LL | fn foo(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 for Bar { fn foo>(self) -> impl Foo { //~^ ERROR: the trait bound `impl Foo: Foo` is not satisfied [E0277] //~| ERROR: the trait bound `Bar: Foo` is not satisfied [E0277] - //~| ERROR: the trait bound `F2: Foo` 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(self) -> impl Foo; + | -------------------------------- definition of `foo` from trait +... +LL | fn foo>(self) -> impl Foo { + | ^^^^^^^ impl has extra requirement `F2: Foo` + error[E0277]: the trait bound `impl Foo: Foo` 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(self) -> impl Foo; | ^^^^^^ required by this bound in `Foo::{synthetic#0}` -error[E0277]: the trait bound `F2: Foo` is not satisfied - --> $DIR/return-dont-satisfy-bounds.rs:8:34 - | -LL | fn foo>(self) -> impl Foo { - | ^^^^^^^^^^^^ the trait `Foo` is not implemented for `F2` - | -note: required by a bound in `>::foo` - --> $DIR/return-dont-satisfy-bounds.rs:8:16 - | -LL | fn foo>(self) -> impl Foo { - | ^^^^^^^ required by this bound in `>::foo` - error[E0277]: the trait bound `Bar: Foo` 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() {}