mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-02 21:17:39 +00:00
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
This commit is contained in:
commit
f17cf744f5
@ -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(
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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 });
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -935,6 +935,7 @@ impl<'a> Builder<'a> {
|
||||
check::RustAnalyzer,
|
||||
check::TestFloatParse,
|
||||
check::Bootstrap,
|
||||
check::RunMakeSupport,
|
||||
check::Compiletest,
|
||||
),
|
||||
Kind::Test => describe!(
|
||||
|
@ -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!(
|
||||
|
35
tests/codegen/bool-select-unpredictable.rs
Normal file
35
tests/codegen/bool-select-unpredictable.rs
Normal file
@ -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)
|
||||
}
|
@ -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)
|
||||
|
@ -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
|
||||
{
|
||||
()
|
||||
}
|
||||
|
@ -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`.
|
||||
|
@ -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`
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
12
tests/ui/impl-trait/in-trait/mismatched-where-clauses.rs
Normal file
12
tests/ui/impl-trait/in-trait/mismatched-where-clauses.rs
Normal file
@ -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() {}
|
12
tests/ui/impl-trait/in-trait/mismatched-where-clauses.stderr
Normal file
12
tests/ui/impl-trait/in-trait/mismatched-where-clauses.stderr
Normal file
@ -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`.
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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`.
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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`.
|
||||
|
54
tests/ui/traits/const-traits/pattern-custom-partial-eq.rs
Normal file
54
tests/ui/traits/const-traits/pattern-custom-partial-eq.rs
Normal file
@ -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() {}
|
Loading…
Reference in New Issue
Block a user