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:
bors 2021-09-15 03:51:03 +00:00
commit cdeba02ff7
26 changed files with 554 additions and 108 deletions

View file

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

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

View file

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

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

View file

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