diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 1d5f463015294..b293317856901 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -795,8 +795,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } }; - let mut nonconst_call_permission = false; - // Attempting to call a trait method? if let Some(trait_id) = tcx.trait_of_item(callee) { trace!("attempting to call a trait method"); @@ -843,22 +841,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } _ if !tcx.is_const_fn_raw(callee) => { - // At this point, it is only legal when the caller is marked with - // #[default_method_body_is_const], and the callee is in the same - // trait. - let callee_trait = tcx.trait_of_item(callee); - if callee_trait.is_some() { - if tcx.has_attr(caller, sym::default_method_body_is_const) { - if tcx.trait_of_item(caller) == callee_trait { - nonconst_call_permission = true; - } - } - } - - if !nonconst_call_permission { - self.check_op(ops::FnCallNonConst(None)); - return; - } + self.check_op(ops::FnCallNonConst(None)); + return; } _ => {} } @@ -915,16 +899,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { let is_intrinsic = tcx.fn_sig(callee).abi() == RustIntrinsic; if !tcx.is_const_fn_raw(callee) { - if tcx.trait_of_item(callee).is_some() { - if tcx.has_attr(callee, sym::default_method_body_is_const) { - // To get to here we must have already found a const impl for the - // trait, but for it to still be non-const can be that the impl is - // using default method bodies. - nonconst_call_permission = true; - } - } - - if !nonconst_call_permission { + // To get to here we must have already found a const impl for the + // trait, but for it to still be non-const can be that the impl is + // using default method bodies. + if !(tcx.trait_of_item(callee).is_some() && tcx.has_attr(callee, sym::default_method_body_is_const)) { self.check_op(ops::FnCallNonConst(None)); return; } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 4e84849bc1e23..1a266685363eb 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -433,7 +433,7 @@ fn virtual_call_violation_for_method<'tcx>( } if tcx - .predicates_of(method.def_id) + .predicates_defined_on(method.def_id) .predicates .iter() // A trait object can't claim to live more than the concrete type, diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index e7b728d491b67..1f27c7ea40555 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1986,6 +1986,17 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { let mut result = tcx.predicates_defined_on(def_id); + if tcx.has_attr(def_id, sym::default_method_body_is_const) { + if let Some(parent) = tcx.parent(def_id).filter(|&did| tcx.is_trait(did)) { + let span = rustc_span::DUMMY_SP; + result.predicates = + tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once(( + ty::TraitRef::identity(tcx, parent).with_constness(ty::BoundConstness::ConstIfConst).to_predicate(tcx), + span, + )))); + } + } + if tcx.is_trait(def_id) { // For traits, add `Self: Trait` predicate. This is // not part of the predicates that a user writes, but it diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index deed9901cc9e4..61d5352be2c26 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1243,7 +1243,8 @@ mod impls { macro_rules! partial_eq_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - impl PartialEq for $t { + #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + impl const PartialEq for $t { #[inline] fn eq(&self, other: &$t) -> bool { (*self) == (*other) } #[inline] @@ -1280,10 +1281,11 @@ mod impls { macro_rules! partial_ord_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - impl PartialOrd for $t { + #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + impl const PartialOrd for $t { #[inline] fn partial_cmp(&self, other: &$t) -> Option { - match (self <= other, self >= other) { + match (*self <= *other, *self >= *other) { (false, false) => None, (false, true) => Some(Greater), (true, false) => Some(Less), @@ -1323,10 +1325,13 @@ mod impls { macro_rules! ord_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - impl PartialOrd for $t { + #[rustc_const_unstable(feature = "const_cmp", issue = "none")] + impl const PartialOrd for $t { #[inline] fn partial_cmp(&self, other: &$t) -> Option { - Some(self.cmp(other)) + Some(if *self < *other { Less } + else if *self == *other { Equal } + else { Greater }) } #[inline] fn lt(&self, other: &$t) -> bool { (*self) < (*other) } diff --git a/src/test/ui/const-generics/issues/issue-90318.rs b/src/test/ui/const-generics/issues/issue-90318.rs index 0c640a5ef7136..d6c48e63bb3ce 100644 --- a/src/test/ui/const-generics/issues/issue-90318.rs +++ b/src/test/ui/const-generics/issues/issue-90318.rs @@ -12,16 +12,14 @@ impl True for If {} fn consume(_val: T) where If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - //~^ ERROR: overly complex generic constant - //~| ERROR: calls in constants are limited to constant functions + //~^ ERROR: can't compare { } fn test() where If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - //~^ ERROR: overly complex generic constant - //~| ERROR: calls in constants are limited to constant functions + //~^ ERROR: can't compare { } diff --git a/src/test/ui/const-generics/issues/issue-90318.stderr b/src/test/ui/const-generics/issues/issue-90318.stderr index 2b8afe2ef09ed..f23946f52d21f 100644 --- a/src/test/ui/const-generics/issues/issue-90318.stderr +++ b/src/test/ui/const-generics/issues/issue-90318.stderr @@ -1,37 +1,27 @@ -error: overly complex generic constant - --> $DIR/issue-90318.rs:14:8 +error[E0277]: can't compare `TypeId` with `TypeId` + --> $DIR/issue-90318.rs:14:28 | LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - | ^^-----------------^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | borrowing is not supported in generic constants + | ^^ no implementation for `TypeId == TypeId` | - = help: consider moving this anonymous constant into a `const` function - = note: this operation may be supported in the future - -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants - --> $DIR/issue-90318.rs:14:10 + = help: the trait `PartialEq` is not implemented for `TypeId` +help: consider extending the `where` bound, but there might be an alternative better way to express this requirement | -LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, TypeId: PartialEq + | ~~~~~~~~~~~~~~~~~~~ -error: overly complex generic constant - --> $DIR/issue-90318.rs:22:8 +error[E0277]: can't compare `TypeId` with `TypeId` + --> $DIR/issue-90318.rs:21:28 | LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - | ^^-----------------^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | borrowing is not supported in generic constants + | ^^ no implementation for `TypeId == TypeId` | - = help: consider moving this anonymous constant into a `const` function - = note: this operation may be supported in the future - -error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants - --> $DIR/issue-90318.rs:22:10 + = help: the trait `PartialEq` is not implemented for `TypeId` +help: consider extending the `where` bound, but there might be an alternative better way to express this requirement | -LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | If<{ TypeId::of::() != TypeId::of::<()>() }>: True, TypeId: PartialEq + | ~~~~~~~~~~~~~~~~~~~ -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/consts/issue-25826.rs b/src/test/ui/consts/issue-25826.rs index d1093c205798a..c340c30a113b5 100644 --- a/src/test/ui/consts/issue-25826.rs +++ b/src/test/ui/consts/issue-25826.rs @@ -1,6 +1,6 @@ fn id(t: T) -> T { t } fn main() { const A: bool = unsafe { id:: as *const () < id:: as *const () }; - //~^ ERROR pointers cannot be reliably compared during const eval + //~^ ERROR can't compare println!("{}", A); } diff --git a/src/test/ui/consts/issue-25826.stderr b/src/test/ui/consts/issue-25826.stderr index 780edd2149fe1..48dc01a1f3000 100644 --- a/src/test/ui/consts/issue-25826.stderr +++ b/src/test/ui/consts/issue-25826.stderr @@ -1,10 +1,15 @@ -error: pointers cannot be reliably compared during const eval - --> $DIR/issue-25826.rs:3:30 +error[E0277]: can't compare `*const ()` with `*const ()` + --> $DIR/issue-25826.rs:3:52 | LL | const A: bool = unsafe { id:: as *const () < id:: as *const () }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ no implementation for `*const () < *const ()` and `*const () > *const ()` | - = note: see issue #53020 for more information + = help: the trait `PartialOrd` is not implemented for `*const ()` +help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement + | +LL | fn main() where *const (): PartialOrd { + | +++++++++++++++++++++++++++ error: aborting due to previous error +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs index 7a0db9c98ea61..a5a413e215359 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs @@ -23,7 +23,7 @@ impl const ConstDefaultFn for ConstImpl { const fn test() { NonConstImpl.a(); - //~^ ERROR calls in constant functions are limited to constant functions, tuple structs and tuple variants + //~^ ERROR the trait bound `NonConstImpl: ConstDefaultFn` is not satisfied ConstImpl.a(); } diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr index 63e4095af2943..e324ef2d8759e 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr @@ -1,9 +1,14 @@ -error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants - --> $DIR/const-default-method-bodies.rs:25:5 +error[E0277]: the trait bound `NonConstImpl: ConstDefaultFn` is not satisfied + --> $DIR/const-default-method-bodies.rs:25:18 | LL | NonConstImpl.a(); - | ^^^^^^^^^^^^^^^^ + | ^ the trait `ConstDefaultFn` is not implemented for `NonConstImpl` + | +help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement + | +LL | const fn test() where NonConstImpl: ConstDefaultFn { + | ++++++++++++++++++++++++++++++++++ error: aborting due to previous error -For more information about this error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-implied-bounds-on-self.rs b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-implied-bounds-on-self.rs new file mode 100644 index 0000000000000..e843d150cfa49 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-implied-bounds-on-self.rs @@ -0,0 +1,17 @@ +// check-pass + +#![feature(const_trait_impl)] +#![feature(const_fn_trait_bound)] + +pub trait Foo { + #[default_method_body_is_const] + fn do_stuff(self) where Self: Sized { + do_stuff_as_foo(self); + } +} + +const fn do_stuff_as_foo(foo: T) { + std::mem::forget(foo); +} + +fn main() {} \ No newline at end of file