Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an implicit Self: ~const Trait bound on default_method_body_is_const methods #92228

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 6 additions & 28 deletions compiler/rustc_const_eval/src/transform/check_consts/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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;
}
_ => {}
}
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/traits/object_safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_typeck/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 10 additions & 5 deletions library/core/src/cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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<Ordering> {
match (self <= other, self >= other) {
match (*self <= *other, *self >= *other) {
(false, false) => None,
(false, true) => Some(Greater),
(true, false) => Some(Less),
Expand Down Expand Up @@ -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<Ordering> {
Some(self.cmp(other))
Some(if *self < *other { Less }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a const hack comment here

else if *self == *other { Equal }
else { Greater })
}
#[inline]
fn lt(&self, other: &$t) -> bool { (*self) < (*other) }
Expand Down
6 changes: 2 additions & 4 deletions src/test/ui/const-generics/issues/issue-90318.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,14 @@ impl True for If<true> {}
fn consume<T: 'static>(_val: T)
where
If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
//~^ ERROR: overly complex generic constant
//~| ERROR: calls in constants are limited to constant functions
//~^ ERROR: can't compare
{
}

fn test<T: 'static>()
where
If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
//~^ ERROR: overly complex generic constant
//~| ERROR: calls in constants are limited to constant functions
//~^ ERROR: can't compare
{
}

Expand Down
42 changes: 16 additions & 26 deletions src/test/ui/const-generics/issues/issue-90318.stderr
Original file line number Diff line number Diff line change
@@ -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::<T>() != 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::<T>() != TypeId::of::<()>() }>: True,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | If<{ TypeId::of::<T>() != 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::<T>() != 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::<T>() != TypeId::of::<()>() }>: True,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | If<{ TypeId::of::<T>() != 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`.
2 changes: 1 addition & 1 deletion src/test/ui/consts/issue-25826.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
fn id<T>(t: T) -> T { t }
fn main() {
const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () };
//~^ ERROR pointers cannot be reliably compared during const eval
//~^ ERROR can't compare
println!("{}", A);
}
13 changes: 9 additions & 4 deletions src/test/ui/consts/issue-25826.stderr
Original file line number Diff line number Diff line change
@@ -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::<u8> as *const () < id::<u16> as *const () };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^ no implementation for `*const () < *const ()` and `*const () > *const ()`
|
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/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`.
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
@@ -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<T: ~const Foo>(foo: T) {
std::mem::forget(foo);
}

fn main() {}