Skip to content

Commit ff7e987

Browse files
committed
fix(core): replace ~const Drop with ~const Destruct
This change was driven by [rust-lang/rust#94901][1]. It's actually more than just renaming - it fixes the irregular meaning of `~const Drop` (“the type can be destructed in a const context”, instead of the regular meaning of “`<T as Drop>::drop is `const fn`”), which the compiler was unable to reconcile in `Drop` bounds and thus necessitated the work- around explained in `[ref:drop_const_bounds]`. This is no longer an issue because `~const Destruct` has a regular meaning. [1]: rust-lang/rust#94901
1 parent 597282b commit ff7e987

File tree

4 files changed

+32
-117
lines changed

4 files changed

+32
-117
lines changed

doc/toolchain_limitations.md

Lines changed: 0 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -224,80 +224,6 @@ impl<C> Cfg<C> {
224224
```
225225

226226

227-
### `[tag:drop_const_bounds]` It's non-trivial for a `Drop` implementation to depend on `TypeParam: ~const Drop`
228-
229-
The following code doesn't compile (which is okay) because `T` might not be `T: const Drop`.
230-
231-
```rust,compile_fail,E0493
232-
#![feature(const_trait_impl)]
233-
#![feature(const_mut_refs)]
234-
#![feature(const_option)]
235-
struct Type<T>(Option<T>);
236-
impl<T> const Drop for Type<T> {
237-
fn drop(&mut self) {
238-
// error[E0493]: destructors cannot be evaluated at compile-time
239-
let _ = self.0.take().unwrap();
240-
}
241-
}
242-
```
243-
244-
The obvious solution is to add `T: ~const Drop` to the `Drop` implementation as well as to the type definition. However, this doesn't work because `~const` is not allowed to appear in the type definition.
245-
246-
```rust,compile_fail,E0367
247-
#![feature(const_trait_impl)]
248-
#![feature(const_mut_refs)]
249-
#![feature(const_option)]
250-
// error: `~const` is not allowed here
251-
struct Type<T: ~const Drop>(Option<T>);
252-
// error[E0367]: `Drop` impl requires `T: ~const Drop` but the struct it is
253-
// implemented for does not
254-
impl<T: ~const Drop> const Drop for Type<T> {
255-
fn drop(&mut self) {
256-
let _ = self.0.take().unwrap();
257-
}
258-
}
259-
```
260-
261-
According to [rust-lang/rust#93028](https://github.com/rust-lang/rust/pull/93028), we can actually remove `~const` from this type definition, and the compiler permits the `Drop` implementation to have an extra `~const`. Unfortunately, this leaves a `Drop` trait bound on the type, which actually cover different types than `~const Drop` does. That's because `T: ~const Drop` means that `T` can be dropped in a constant context (n.b. this is [a special case for `Drop`](https://internals.rust-lang.org/t/pre-rfc-revamped-const-trait-impl-aka-rfc-2632/15192#const-drop-in-generic-code-6) and doesn't apply to other traits), while `T: Drop` means that `T` has a user-defined `Drop` implementation.
262-
263-
```rust,compile_fail,E0277
264-
#![feature(const_trait_impl)]
265-
#![feature(const_mut_refs)]
266-
#![feature(const_option)]
267-
struct Type<T: Drop>(Option<T>);
268-
impl<T: ~const Drop> const Drop for Type<T> {
269-
fn drop(&mut self) {
270-
let _ = self.0.take().unwrap();
271-
}
272-
}
273-
// error[E0277]: the trait bound `(): Drop` is not satisfied
274-
let _ = Type(Some(()));
275-
```
276-
277-
A work-around is to enclose `T` in a container that unconditionally implements `const Drop`.
278-
279-
```rust
280-
#![feature(const_trait_impl)]
281-
#![feature(const_mut_refs)]
282-
#![feature(const_option)]
283-
struct UserDrop<T>(T);
284-
impl<T> const Drop for UserDrop<T> {
285-
fn drop(&mut self) {}
286-
}
287-
struct Type<T>(Option<T>) where UserDrop<T>: Drop;
288-
impl<T> const Drop for Type<T>
289-
where
290-
UserDrop<T>: ~const Drop,
291-
{
292-
fn drop(&mut self) {
293-
let _ = UserDrop(self.0.take().unwrap());
294-
}
295-
}
296-
let _ = Type(Some(()));
297-
const _: () = { let _ = Type(Some(())); };
298-
```
299-
300-
301227
### `[tag:const_closures]` Closures can't be `impl const Fn`
302228

303229
```rust

src/r3_core/src/bind/sorter.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,10 @@
4949
//!
5050
// FIXME: We might be able to improve the interface when `ComptimeVec` is not
5151
// restricted to "comptime" anymore
52-
use core::ops::{Deref, DerefMut, Index, IndexMut};
52+
use core::{
53+
marker::Destruct,
54+
ops::{Deref, DerefMut, Index, IndexMut},
55+
};
5356

5457
use super::{BindBorrowType, BindUsage};
5558
use crate::utils::{
@@ -538,12 +541,12 @@ trait MyIterator {
538541
}
539542

540543
trait GraphAccess<VertexRef> {
541-
type VertexIter<'a>: ~const MyIterator<Item = VertexRef> + ~const Drop + 'a
544+
type VertexIter<'a>: ~const MyIterator<Item = VertexRef> + ~const Destruct + 'a
542545
where
543546
Self: 'a;
544547
fn vertices(&self) -> Self::VertexIter<'_>;
545548

546-
type SuccessorIter<'a>: ~const MyIterator<Item = VertexRef> + ~const Drop + 'a
549+
type SuccessorIter<'a>: ~const MyIterator<Item = VertexRef> + ~const Destruct + 'a
547550
where
548551
Self: 'a;
549552
fn successors(&self, v: &VertexRef) -> Self::SuccessorIter<'_>;
@@ -597,9 +600,9 @@ const fn topological_sort<
597600
where
598601
Graph: ~const GraphAccess<VertexRef>,
599602
// [ref:const_trait_not_implied] necessitates `: ~const MyIterator`
600-
Graph::VertexIter<'a>: ~const MyIterator + ~const Drop,
603+
Graph::VertexIter<'a>: ~const MyIterator + ~const Destruct,
601604
// [ref:const_trait_not_implied] necessitates `: ~const MyIterator`
602-
Graph::SuccessorIter<'a>: ~const MyIterator + ~const Drop,
605+
Graph::SuccessorIter<'a>: ~const MyIterator + ~const Destruct,
603606
VertexRef: Copy,
604607
VertexRefLessThan: ~const FnMut(&VertexRef, &VertexRef) -> bool,
605608
// `~const Deref[Mut]` isn't implied because of

src/r3_core/src/utils/binary_heap/mod.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
//!
33
//! The implementation is mostly based on the Rust standard library's
44
//! `BinaryHeap`.
5+
use core::marker::Destruct;
6+
57
mod helpers;
68
#[cfg(test)]
79
mod tests;
@@ -31,36 +33,36 @@ pub trait BinaryHeap: VecLike {
3133
/// Remove the least item from the heap and return it.
3234
fn heap_pop<Ctx>(&mut self, ctx: Ctx) -> Option<Self::Element>
3335
where
34-
Ctx: ~const BinaryHeapCtx<Self::Element> + ~const Drop;
36+
Ctx: ~const BinaryHeapCtx<Self::Element> + ~const Destruct;
3537

3638
/// Remove the item at the specified position and return it.
3739
fn heap_remove<Ctx>(&mut self, i: usize, ctx: Ctx) -> Option<Self::Element>
3840
where
39-
Ctx: ~const BinaryHeapCtx<Self::Element> + ~const Drop;
41+
Ctx: ~const BinaryHeapCtx<Self::Element> + ~const Destruct;
4042

4143
/// Push an item onto the heap and return its position.
4244
fn heap_push<Ctx>(&mut self, item: Self::Element, ctx: Ctx) -> usize
4345
where
44-
Ctx: ~const BinaryHeapCtx<Self::Element> + ~const Drop;
46+
Ctx: ~const BinaryHeapCtx<Self::Element> + ~const Destruct;
4547
}
4648

4749
impl<T> const BinaryHeap for T
4850
where
4951
// `~const Deref` isn't implied because of
5052
// [ref:veclike_const_supertrait]
5153
T: ~const VecLike + ~const core::ops::Deref + ~const core::ops::DerefMut,
52-
T::Element: ~const Drop,
54+
T::Element: ~const Destruct,
5355
{
5456
fn heap_pop<Ctx>(&mut self, ctx: Ctx) -> Option<Self::Element>
5557
where
56-
Ctx: ~const BinaryHeapCtx<Self::Element> + ~const Drop,
58+
Ctx: ~const BinaryHeapCtx<Self::Element> + ~const Destruct,
5759
{
5860
self.heap_remove(0, ctx)
5961
}
6062

6163
fn heap_remove<Ctx>(&mut self, i: usize, mut ctx: Ctx) -> Option<Self::Element>
6264
where
63-
Ctx: ~const BinaryHeapCtx<Self::Element> + ~const Drop,
65+
Ctx: ~const BinaryHeapCtx<Self::Element> + ~const Destruct,
6466
{
6567
if i >= self.len() {
6668
return None;
@@ -94,7 +96,7 @@ where
9496

9597
fn heap_push<Ctx>(&mut self, item: Self::Element, ctx: Ctx) -> usize
9698
where
97-
Ctx: ~const BinaryHeapCtx<Self::Element> + ~const Drop,
99+
Ctx: ~const BinaryHeapCtx<Self::Element> + ~const Destruct,
98100
{
99101
let i = self.len();
100102
self.push(item);
@@ -127,8 +129,8 @@ const unsafe fn sift_up<Element, Ctx>(
127129
mut ctx: Ctx,
128130
) -> usize
129131
where
130-
Ctx: ~const BinaryHeapCtx<Element> + ~const Drop,
131-
Element: ~const Drop,
132+
Ctx: ~const BinaryHeapCtx<Element> + ~const Destruct,
133+
Element: ~const Destruct,
132134
{
133135
unsafe {
134136
// Take out the value at `pos` and create a hole.
@@ -163,8 +165,8 @@ where
163165
/// `pos` must point to an element within `this`.
164166
const unsafe fn sift_down<Element, Ctx>(this: &mut [Element], pos: usize, mut ctx: Ctx)
165167
where
166-
Ctx: ~const BinaryHeapCtx<Element> + ~const Drop,
167-
Element: ~const Drop,
168+
Ctx: ~const BinaryHeapCtx<Element> + ~const Destruct,
169+
Element: ~const Destruct,
168170
{
169171
let end = this.len();
170172
unsafe {

src/r3_core/src/utils/vec.rs

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,17 @@
1-
use core::{alloc::Layout, ops, ptr::NonNull};
1+
use core::{alloc::Layout, marker::Destruct, ops, ptr::NonNull};
22

33
use super::{AllocError, Allocator, ConstAllocator};
44

5-
#[doc(hidden)]
6-
pub struct UserDrop<T>(T);
7-
8-
impl<T> const Drop for UserDrop<T> {
9-
#[inline]
10-
fn drop(&mut self) {}
11-
}
12-
135
/// `Vec` that can only be used in a constant context.
146
#[doc(hidden)]
15-
#[allow(drop_bounds)] // Due to the work-around for [ref:drop_const_bounds]
16-
pub struct ComptimeVec<T>
17-
where
18-
// Work-around for [ref:drop_const_bounds]
19-
UserDrop<T>: Drop,
20-
{
7+
pub struct ComptimeVec<T: Destruct> {
218
ptr: NonNull<T>,
229
len: usize,
2310
capacity: usize,
2411
allocator: ConstAllocator,
2512
}
2613

27-
impl<T: ~const Clone + ~const Drop> const Clone for ComptimeVec<T> {
14+
impl<T: ~const Clone + ~const Destruct> const Clone for ComptimeVec<T> {
2815
fn clone(&self) -> Self {
2916
// FIXME: Work-around for a mysterious error saying "the trait bound
3017
// `for<'r> fn(&'r T) -> T {<T as Clone>::clone}: ~const FnMut<(&T,)>`
@@ -37,16 +24,10 @@ impl<T: ~const Clone + ~const Drop> const Clone for ComptimeVec<T> {
3724
}
3825
}
3926

40-
impl<T> const Drop for ComptimeVec<T>
41-
where
42-
// Work-around for [ref:drop_const_bounds]
43-
UserDrop<T>: ~const Drop,
44-
{
27+
impl<T: ~const Destruct> const Drop for ComptimeVec<T> {
4528
fn drop(&mut self) {
4629
if core::mem::needs_drop::<T>() {
47-
// Wrap `T` with `UserDrop` before dropping to work around
48-
// [ref:drop_const_bounds]
49-
while self.pop().map(UserDrop).is_some() {}
30+
while self.pop().is_some() {}
5031
}
5132

5233
// Safety: The referent is a valid heap allocation from `self.allocator`,
@@ -133,7 +114,10 @@ impl<T> ComptimeVec<T> {
133114

134115
/// Return a `ComptimeVec` of the same `len` as `self` with function `f`
135116
/// applied to each element in order.
136-
pub const fn map<F: ~const FnMut(&T) -> U + ~const Drop, U>(&self, mut f: F) -> ComptimeVec<U> {
117+
pub const fn map<F: ~const FnMut(&T) -> U + ~const Destruct, U>(
118+
&self,
119+
mut f: F,
120+
) -> ComptimeVec<U> {
137121
let mut out = ComptimeVec::with_capacity_in(self.len, self.allocator.clone());
138122
let mut i = 0;
139123
while i < self.len() {
@@ -146,7 +130,7 @@ impl<T> ComptimeVec<T> {
146130
/// Remove all elements.
147131
pub const fn clear(&mut self)
148132
where
149-
T: ~const Drop,
133+
T: ~const Destruct,
150134
{
151135
if core::mem::needs_drop::<T>() {
152136
while self.pop().is_some() {}
@@ -217,7 +201,7 @@ macro_rules! vec_position {
217201
}
218202

219203
/// Unwrap `Result<T, AllocError>`.
220-
const fn unwrap_alloc_error<T: ~const Drop>(x: Result<T, AllocError>) -> T {
204+
const fn unwrap_alloc_error<T: ~const Destruct>(x: Result<T, AllocError>) -> T {
221205
match x {
222206
Ok(x) => x,
223207
Err(AllocError) => panic!("compile-time heap allocation failed"),

0 commit comments

Comments
 (0)