Auto merge of #88558 - fee1-dead:const-drop, r=oli-obk
Const drop
The changes are pretty primitive at this point. But at least it works. ^-^
Problems with the current change that I can think of now:
- [x] `~const Drop` shouldn't change anything in the non-const world.
- [x] types that do not have drop glues shouldn't fail to satisfy `~const Drop` in const contexts. `struct S { a: u8, b: u16 }` This might not fail for `needs_non_const_drop`, but it will fail in `rustc_trait_selection`.
- [x] The current change accepts types that have `const Drop` impls but have non-const `Drop` glue.
Fixes #88424.
Significant Changes:
- `~const Drop` is no longer treated as a normal trait bound. In non-const contexts, this bound has no effect, but in const contexts, this restricts the input type and all of its transitive fields to either a) have a `const Drop` impl or b) can be trivially dropped (i.e. no drop glue)
- `T: ~const Drop` will not be linted like `T: Drop`.
- Instead of recursing and iterating through the type in `rustc_mir::transform::check_consts`, we use the trait system to special case `~const Drop`. See [`rustc_trait_selection::...::candidate_assembly#assemble_const_drop_candidates`](https://github.com/fee1-dead/rust/blob/const-drop/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs#L817) and others.
Changes not related to `const Drop`ping and/or changes that are insignificant:
- `Node.constness_for_typeck` no longer returns `hir::Constness::Const` for type aliases in traits. This was previously used to hack how we determine default bound constness for items. But because we now use an explicit opt-in, it is no longer needed.
- Removed `is_const_impl_raw` query. We have `impl_constness`, and the only existing use of that query uses `HirId`, which means we can just operate it with hir.
- `ty::Destructor` now has a field `constness`, which represents the constness of the destructor.
r? `@oli-obk`
This commit is contained in:
commit
cdeba02ff7
26 changed files with 554 additions and 108 deletions
|
|
@ -0,0 +1,59 @@
|
|||
error: `~const` is not allowed here
|
||||
--> $DIR/const-drop-fail.rs:27:35
|
||||
|
|
||||
LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions
|
||||
|
||||
error[E0277]: the trait bound `NonTrivialDrop: Drop` is not satisfied
|
||||
--> $DIR/const-drop-fail.rs:45:5
|
||||
|
|
||||
LL | NonTrivialDrop,
|
||||
| ^^^^^^^^^^^^^^ the trait `Drop` is not implemented for `NonTrivialDrop`
|
||||
|
|
||||
note: required by a bound in `check`
|
||||
--> $DIR/const-drop-fail.rs:36:19
|
||||
|
|
||||
LL | const fn check<T: ~const Drop>(_: T) {}
|
||||
| ^^^^^^^^^^^ required by this bound in `check`
|
||||
|
||||
error[E0277]: the trait bound `ConstImplWithDropGlue: Drop` is not satisfied
|
||||
--> $DIR/const-drop-fail.rs:47:5
|
||||
|
|
||||
LL | ConstImplWithDropGlue(NonTrivialDrop),
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Drop` is not implemented for `ConstImplWithDropGlue`
|
||||
|
|
||||
note: required by a bound in `check`
|
||||
--> $DIR/const-drop-fail.rs:36:19
|
||||
|
|
||||
LL | const fn check<T: ~const Drop>(_: T) {}
|
||||
| ^^^^^^^^^^^ required by this bound in `check`
|
||||
|
||||
error[E0277]: the trait bound `NonTrivialDrop: A` is not satisfied
|
||||
--> $DIR/const-drop-fail.rs:49:5
|
||||
|
|
||||
LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `A` is not implemented for `NonTrivialDrop`
|
||||
|
|
||||
note: required by `ConstDropImplWithBounds`
|
||||
--> $DIR/const-drop-fail.rs:27:1
|
||||
|
|
||||
LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: the trait bound `NonTrivialDrop: A` is not satisfied
|
||||
--> $DIR/const-drop-fail.rs:49:5
|
||||
|
|
||||
LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `A` is not implemented for `NonTrivialDrop`
|
||||
|
|
||||
note: required by a bound in `ConstDropImplWithBounds`
|
||||
--> $DIR/const-drop-fail.rs:27:35
|
||||
|
|
||||
LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
|
||||
| ^^^^^^^^ required by this bound in `ConstDropImplWithBounds`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
54
src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs
Normal file
54
src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// revisions: stock precise
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(const_mut_refs)]
|
||||
#![feature(const_fn_trait_bound)]
|
||||
#![cfg_attr(precise, feature(const_precise_live_drops))]
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
struct NonTrivialDrop;
|
||||
|
||||
impl Drop for NonTrivialDrop {
|
||||
fn drop(&mut self) {
|
||||
println!("Non trivial drop");
|
||||
}
|
||||
}
|
||||
|
||||
struct ConstImplWithDropGlue(NonTrivialDrop);
|
||||
|
||||
impl const Drop for ConstImplWithDropGlue {
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
trait A { fn a() { println!("A"); } }
|
||||
|
||||
impl A for NonTrivialDrop {}
|
||||
|
||||
struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
|
||||
//~^ ERROR `~const` is not allowed
|
||||
|
||||
impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
|
||||
fn drop(&mut self) {
|
||||
T::a();
|
||||
}
|
||||
}
|
||||
|
||||
const fn check<T: ~const Drop>(_: T) {}
|
||||
|
||||
macro_rules! check_all {
|
||||
($($exp:expr),*$(,)?) => {$(
|
||||
const _: () = check($exp);
|
||||
)*};
|
||||
}
|
||||
|
||||
check_all! {
|
||||
NonTrivialDrop,
|
||||
//~^ ERROR the trait bound
|
||||
ConstImplWithDropGlue(NonTrivialDrop),
|
||||
//~^ ERROR the trait bound
|
||||
ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
|
||||
//~^ ERROR the trait bound
|
||||
//~| ERROR the trait bound
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
error: `~const` is not allowed here
|
||||
--> $DIR/const-drop-fail.rs:27:35
|
||||
|
|
||||
LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions
|
||||
|
||||
error[E0277]: the trait bound `NonTrivialDrop: Drop` is not satisfied
|
||||
--> $DIR/const-drop-fail.rs:45:5
|
||||
|
|
||||
LL | NonTrivialDrop,
|
||||
| ^^^^^^^^^^^^^^ the trait `Drop` is not implemented for `NonTrivialDrop`
|
||||
|
|
||||
note: required by a bound in `check`
|
||||
--> $DIR/const-drop-fail.rs:36:19
|
||||
|
|
||||
LL | const fn check<T: ~const Drop>(_: T) {}
|
||||
| ^^^^^^^^^^^ required by this bound in `check`
|
||||
|
||||
error[E0277]: the trait bound `ConstImplWithDropGlue: Drop` is not satisfied
|
||||
--> $DIR/const-drop-fail.rs:47:5
|
||||
|
|
||||
LL | ConstImplWithDropGlue(NonTrivialDrop),
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Drop` is not implemented for `ConstImplWithDropGlue`
|
||||
|
|
||||
note: required by a bound in `check`
|
||||
--> $DIR/const-drop-fail.rs:36:19
|
||||
|
|
||||
LL | const fn check<T: ~const Drop>(_: T) {}
|
||||
| ^^^^^^^^^^^ required by this bound in `check`
|
||||
|
||||
error[E0277]: the trait bound `NonTrivialDrop: A` is not satisfied
|
||||
--> $DIR/const-drop-fail.rs:49:5
|
||||
|
|
||||
LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `A` is not implemented for `NonTrivialDrop`
|
||||
|
|
||||
note: required by `ConstDropImplWithBounds`
|
||||
--> $DIR/const-drop-fail.rs:27:1
|
||||
|
|
||||
LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: the trait bound `NonTrivialDrop: A` is not satisfied
|
||||
--> $DIR/const-drop-fail.rs:49:5
|
||||
|
|
||||
LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `A` is not implemented for `NonTrivialDrop`
|
||||
|
|
||||
note: required by a bound in `ConstDropImplWithBounds`
|
||||
--> $DIR/const-drop-fail.rs:27:35
|
||||
|
|
||||
LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
|
||||
| ^^^^^^^^ required by this bound in `ConstDropImplWithBounds`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
81
src/test/ui/rfc-2632-const-trait-impl/const-drop.rs
Normal file
81
src/test/ui/rfc-2632-const-trait-impl/const-drop.rs
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
// run-pass
|
||||
// revisions: stock precise
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(const_fn_trait_bound)]
|
||||
#![feature(const_mut_refs)]
|
||||
#![feature(const_panic)]
|
||||
#![cfg_attr(precise, feature(const_precise_live_drops))]
|
||||
|
||||
struct S<'a>(&'a mut u8);
|
||||
|
||||
impl<'a> const Drop for S<'a> {
|
||||
fn drop(&mut self) {
|
||||
*self.0 += 1;
|
||||
}
|
||||
}
|
||||
|
||||
const fn a<T: ~const Drop>(_: T) {}
|
||||
|
||||
const fn b() -> u8 {
|
||||
let mut c = 0;
|
||||
let _ = S(&mut c);
|
||||
a(S(&mut c));
|
||||
c
|
||||
}
|
||||
|
||||
const C: u8 = b();
|
||||
|
||||
macro_rules! implements_const_drop {
|
||||
($($exp:expr),*$(,)?) => {
|
||||
$(
|
||||
const _: () = a($exp);
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
mod t {
|
||||
pub struct Foo;
|
||||
pub enum Bar { A }
|
||||
pub fn foo() {}
|
||||
pub struct ConstDrop;
|
||||
|
||||
impl const Drop for ConstDrop {
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
pub struct HasConstDrop(pub ConstDrop);
|
||||
pub struct TrivialFields(pub u8, pub i8, pub usize, pub isize);
|
||||
}
|
||||
|
||||
use t::*;
|
||||
|
||||
implements_const_drop! {
|
||||
1u8,
|
||||
2,
|
||||
3.0,
|
||||
Foo,
|
||||
Bar::A,
|
||||
foo,
|
||||
ConstDrop,
|
||||
HasConstDrop(ConstDrop),
|
||||
TrivialFields(1, 2, 3, 4),
|
||||
&1,
|
||||
&1 as *const i32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
struct HasDropGlue(Box<u8>);
|
||||
struct HasDropImpl;
|
||||
impl Drop for HasDropImpl {
|
||||
fn drop(&mut self) {
|
||||
println!("not trivial drop");
|
||||
}
|
||||
}
|
||||
|
||||
// These types should pass because ~const in a non-const context should have no effect.
|
||||
a(HasDropGlue(Box::new(0)));
|
||||
a(HasDropImpl);
|
||||
|
||||
assert_eq!(C, 2);
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// check-pass
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(const_fn_trait_bound)]
|
||||
|
||||
struct S;
|
||||
|
||||
trait A {}
|
||||
trait B {}
|
||||
|
||||
impl const A for S {}
|
||||
impl const B for S {}
|
||||
|
||||
impl S {
|
||||
const fn a<T: ~const A>() where T: ~const B {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const _: () = S::a::<S>();
|
||||
|
||||
fn main() {}
|
||||
Loading…
Add table
Add a link
Reference in a new issue