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:
bors 2025-01-04 10:02:59 +00:00
commit f17cf744f5
25 changed files with 270 additions and 86 deletions

View File

@ -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(

View File

@ -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(),
}
}

View File

@ -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,

View File

@ -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,
}

View File

@ -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

View File

@ -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 CPUs 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)
}
}

View File

@ -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]

View File

@ -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

View File

@ -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 });

View File

@ -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);
}

View File

@ -935,6 +935,7 @@ impl<'a> Builder<'a> {
check::RustAnalyzer,
check::TestFloatParse,
check::Bootstrap,
check::RunMakeSupport,
check::Compiletest,
),
Kind::Test => describe!(

View File

@ -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!(

View 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)
}

View File

@ -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)

View File

@ -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
{
()
}

View File

@ -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`.

View File

@ -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`

View File

@ -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
}
}

View 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() {}

View 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`.

View File

@ -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
}
}

View File

@ -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`.

View File

@ -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)
}

View File

@ -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`.

View 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() {}