Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit a13b13f

Browse files
committed
Const drop selection candidates
1 parent 894ce92 commit a13b13f

File tree

9 files changed

+210
-23
lines changed

9 files changed

+210
-23
lines changed

compiler/rustc_middle/src/traits/mod.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,9 @@ pub enum ImplSource<'tcx, N> {
529529

530530
/// ImplSource for a trait alias.
531531
TraitAlias(ImplSourceTraitAliasData<'tcx, N>),
532+
533+
/// ImplSource for a `const Drop` implementation.
534+
ConstDrop(ImplSourceConstDropData),
532535
}
533536

534537
impl<'tcx, N> ImplSource<'tcx, N> {
@@ -543,7 +546,8 @@ impl<'tcx, N> ImplSource<'tcx, N> {
543546
ImplSource::Object(d) => d.nested,
544547
ImplSource::FnPointer(d) => d.nested,
545548
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
546-
| ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(),
549+
| ImplSource::Pointee(ImplSourcePointeeData)
550+
| ImplSource::ConstDrop(ImplSourceConstDropData) => Vec::new(),
547551
ImplSource::TraitAlias(d) => d.nested,
548552
ImplSource::TraitUpcasting(d) => d.nested,
549553
}
@@ -560,7 +564,8 @@ impl<'tcx, N> ImplSource<'tcx, N> {
560564
ImplSource::Object(d) => &d.nested[..],
561565
ImplSource::FnPointer(d) => &d.nested[..],
562566
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
563-
| ImplSource::Pointee(ImplSourcePointeeData) => &[],
567+
| ImplSource::Pointee(ImplSourcePointeeData)
568+
| ImplSource::ConstDrop(ImplSourceConstDropData) => &[],
564569
ImplSource::TraitAlias(d) => &d.nested[..],
565570
ImplSource::TraitUpcasting(d) => &d.nested[..],
566571
}
@@ -621,6 +626,9 @@ impl<'tcx, N> ImplSource<'tcx, N> {
621626
nested: d.nested.into_iter().map(f).collect(),
622627
})
623628
}
629+
ImplSource::ConstDrop(ImplSourceConstDropData) => {
630+
ImplSource::ConstDrop(ImplSourceConstDropData)
631+
}
624632
}
625633
}
626634
}
@@ -712,6 +720,9 @@ pub struct ImplSourceDiscriminantKindData;
712720
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
713721
pub struct ImplSourcePointeeData;
714722

723+
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
724+
pub struct ImplSourceConstDropData;
725+
715726
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
716727
pub struct ImplSourceTraitAliasData<'tcx, N> {
717728
pub alias_def_id: DefId,

compiler/rustc_middle/src/traits/select.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@ pub enum SelectionCandidate<'tcx> {
143143
BuiltinObjectCandidate,
144144

145145
BuiltinUnsizeCandidate,
146+
147+
/// Implementation of `const Drop`.
148+
ConstDropCandidate,
146149
}
147150

148151
/// The result of trait evaluation. The order is important

compiler/rustc_middle/src/traits/structural_impls.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
3232
super::ImplSource::TraitAlias(ref d) => write!(f, "{:?}", d),
3333

3434
super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d),
35+
36+
super::ImplSource::ConstDrop(ref d) => write!(f, "{:?}", d),
3537
}
3638
}
3739
}
@@ -125,4 +127,5 @@ TrivialTypeFoldableAndLiftImpls! {
125127
super::IfExpressionCause,
126128
super::ImplSourceDiscriminantKindData,
127129
super::ImplSourcePointeeData,
130+
super::ImplSourceConstDropData,
128131
}

compiler/rustc_trait_selection/src/traits/project.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1477,7 +1477,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
14771477
}
14781478
super::ImplSource::AutoImpl(..)
14791479
| super::ImplSource::Builtin(..)
1480-
| super::ImplSource::TraitUpcasting(_) => {
1480+
| super::ImplSource::TraitUpcasting(_)
1481+
| super::ImplSource::ConstDrop(_) => {
14811482
// These traits have no associated types.
14821483
selcx.tcx().sess.delay_span_bug(
14831484
obligation.cause.span,
@@ -1549,7 +1550,8 @@ fn confirm_select_candidate<'cx, 'tcx>(
15491550
| super::ImplSource::Param(..)
15501551
| super::ImplSource::Builtin(..)
15511552
| super::ImplSource::TraitUpcasting(_)
1552-
| super::ImplSource::TraitAlias(..) => {
1553+
| super::ImplSource::TraitAlias(..)
1554+
| super::ImplSource::ConstDrop(_) => {
15531555
// we don't create Select candidates with this kind of resolution
15541556
span_bug!(
15551557
obligation.cause.span,

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use rustc_hir as hir;
99
use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
1010
use rustc_middle::ty::print::with_no_trimmed_paths;
11-
use rustc_middle::ty::{self, TypeFoldable};
11+
use rustc_middle::ty::{self, Ty, TypeFoldable};
1212
use rustc_target::spec::abi::Abi;
1313

1414
use crate::traits::coherence::Conflict;
@@ -277,6 +277,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
277277
self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates);
278278
} else if lang_items.unsize_trait() == Some(def_id) {
279279
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
280+
} else if lang_items.drop_trait() == Some(def_id)
281+
&& obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst
282+
{
283+
if self.is_in_const_context {
284+
self.assemble_const_drop_candidates(obligation, &mut candidates)?;
285+
} else {
286+
// `~const Drop` when we are not in a const context has no effect.
287+
candidates.vec.push(ConstDropCandidate)
288+
}
280289
} else {
281290
if lang_items.clone_trait() == Some(def_id) {
282291
// Same builtin conditions as `Copy`, i.e., every type which has builtin support
@@ -803,4 +812,103 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
803812
}
804813
}
805814
}
815+
816+
fn assemble_const_drop_candidates(
817+
&mut self,
818+
obligation: &TraitObligation<'tcx>,
819+
candidates: &mut SelectionCandidateSet<'tcx>,
820+
) -> Result<(), SelectionError<'tcx>> {
821+
let mut stack: Vec<(Ty<'tcx>, usize)> = vec![(obligation.self_ty().skip_binder(), 0)];
822+
823+
while let Some((ty, depth)) = stack.pop() {
824+
self.check_recursion_depth(depth, obligation)?;
825+
let mut copy_candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
826+
let mut copy_obligation =
827+
obligation.with(obligation.predicate.rebind(ty::TraitPredicate {
828+
trait_ref: ty::TraitRef {
829+
def_id: self.tcx().require_lang_item(hir::LangItem::Copy, None),
830+
substs: self.tcx().mk_substs_trait(ty, &[]),
831+
},
832+
constness: ty::BoundConstness::NotConst,
833+
}));
834+
copy_obligation.recursion_depth = depth + 1;
835+
self.assemble_candidates_from_impls(&copy_obligation, &mut copy_candidates);
836+
let copy_conditions = self.copy_clone_conditions(&copy_obligation);
837+
self.assemble_builtin_bound_candidates(copy_conditions, &mut copy_candidates);
838+
if !copy_candidates.vec.is_empty() {
839+
continue;
840+
}
841+
842+
match ty.kind() {
843+
ty::Int(_)
844+
| ty::Uint(_)
845+
| ty::Float(_)
846+
| ty::Infer(ty::IntVar(_))
847+
| ty::Infer(ty::FloatVar(_))
848+
| ty::FnPtr(_)
849+
| ty::Never
850+
| ty::Ref(..)
851+
| ty::FnDef(..)
852+
| ty::RawPtr(_)
853+
| ty::Bool
854+
| ty::Char
855+
| ty::Str
856+
| ty::Foreign(_) => {} // Do nothing. These types satisfy `const Drop`.
857+
858+
ty::Adt(def, subst) => {
859+
let mut set = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
860+
self.assemble_candidates_from_impls(obligation, &mut set);
861+
if set
862+
.vec
863+
.into_iter()
864+
.find(|candidate| {
865+
if let SelectionCandidate::ImplCandidate(did) = candidate {
866+
matches!(self.tcx().impl_constness(*did), hir::Constness::NotConst)
867+
} else {
868+
false
869+
}
870+
})
871+
.is_none()
872+
{
873+
// could not find a const impl for Drop, iterate over its fields.
874+
stack
875+
.extend(def.all_fields().map(|f| (f.ty(self.tcx(), subst), depth + 1)));
876+
}
877+
}
878+
879+
ty::Array(ty, _) => stack.push((ty, depth + 1)),
880+
881+
ty::Tuple(_) => stack.extend(ty.tuple_fields().map(|t| (t, depth + 1))),
882+
883+
ty::Closure(_, substs) => {
884+
stack.extend(substs.as_closure().upvar_tys().map(|t| (t, depth + 1)))
885+
}
886+
887+
ty::Generator(_, substs, _) => {
888+
let substs = substs.as_generator();
889+
stack.extend(substs.upvar_tys().map(|t| (t, depth + 1)));
890+
stack.push((substs.witness(), depth + 1));
891+
}
892+
893+
ty::GeneratorWitness(tys) => stack.extend(
894+
self.tcx().erase_late_bound_regions(*tys).iter().map(|t| (t, depth + 1)),
895+
),
896+
897+
ty::Slice(ty) => stack.push((ty, depth + 1)),
898+
899+
ty::Opaque(..)
900+
| ty::Dynamic(..)
901+
| ty::Error(_)
902+
| ty::Bound(..)
903+
| ty::Infer(_)
904+
| ty::Placeholder(_)
905+
| ty::Projection(..)
906+
| ty::Param(..) => return Ok(()),
907+
}
908+
}
909+
// all types have passed.
910+
candidates.vec.push(ConstDropCandidate);
911+
912+
Ok(())
913+
}
806914
}

compiler/rustc_trait_selection/src/traits/select/confirmation.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use crate::traits::TraitNotObjectSafe;
2828
use crate::traits::VtblSegment;
2929
use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation};
3030
use crate::traits::{
31-
ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
31+
ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData, ImplSourceConstDropData,
3232
ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData,
3333
ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData,
3434
ImplSourceTraitUpcastingData, ImplSourceUserDefinedData,
@@ -124,6 +124,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
124124
let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?;
125125
Ok(ImplSource::TraitUpcasting(data))
126126
}
127+
128+
ConstDropCandidate => Ok(ImplSource::ConstDrop(ImplSourceConstDropData)),
127129
}
128130
}
129131

compiler/rustc_trait_selection/src/traits/select/mod.rs

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,19 +1038,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10381038
it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1);
10391039
}
10401040

1041-
/// Checks that the recursion limit has not been exceeded.
1042-
///
1043-
/// The weird return type of this function allows it to be used with the `try` (`?`)
1044-
/// operator within certain functions.
1045-
fn check_recursion_limit<T: Display + TypeFoldable<'tcx>, V: Display + TypeFoldable<'tcx>>(
1041+
fn check_recursion_depth<T: Display + TypeFoldable<'tcx>>(
10461042
&self,
1047-
obligation: &Obligation<'tcx, T>,
1048-
error_obligation: &Obligation<'tcx, V>,
1043+
depth: usize,
1044+
error_obligation: &Obligation<'tcx, T>,
10491045
) -> Result<(), OverflowError> {
1050-
if !self.infcx.tcx.recursion_limit().value_within_limit(obligation.recursion_depth) {
1046+
if !self.infcx.tcx.recursion_limit().value_within_limit(depth) {
10511047
match self.query_mode {
10521048
TraitQueryMode::Standard => {
1053-
self.infcx().report_overflow_error(error_obligation, true);
1049+
self.infcx.report_overflow_error(error_obligation, true);
10541050
}
10551051
TraitQueryMode::Canonical => {
10561052
return Err(OverflowError);
@@ -1060,6 +1056,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10601056
Ok(())
10611057
}
10621058

1059+
/// Checks that the recursion limit has not been exceeded.
1060+
///
1061+
/// The weird return type of this function allows it to be used with the `try` (`?`)
1062+
/// operator within certain functions.
1063+
fn check_recursion_limit<T: Display + TypeFoldable<'tcx>, V: Display + TypeFoldable<'tcx>>(
1064+
&self,
1065+
obligation: &Obligation<'tcx, T>,
1066+
error_obligation: &Obligation<'tcx, V>,
1067+
) -> Result<(), OverflowError> {
1068+
self.check_recursion_depth(obligation.recursion_depth, error_obligation)
1069+
}
1070+
10631071
fn in_task<OP, R>(&mut self, op: OP) -> (R, DepNodeIndex)
10641072
where
10651073
OP: FnOnce(&mut Self) -> R,
@@ -1079,10 +1087,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10791087
let tcx = self.tcx();
10801088
// Respect const trait obligations
10811089
if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
1082-
if Some(obligation.predicate.skip_binder().trait_ref.def_id)
1083-
!= tcx.lang_items().sized_trait()
1084-
// const Sized bounds are skipped
1085-
{
10861090
match candidate {
10871091
// const impl
10881092
ImplCandidate(def_id)
@@ -1097,12 +1101,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10971101
// generator, this will raise error in other places
10981102
// or ignore error with const_async_blocks feature
10991103
GeneratorCandidate => {}
1104+
ConstDropCandidate => {}
11001105
_ => {
11011106
// reject all other types of candidates
11021107
return Err(Unimplemented);
11031108
}
11041109
}
1105-
}
11061110
}
11071111
// Treat negative impls as unimplemented, and reservation impls as ambiguity.
11081112
if let ImplCandidate(def_id) = candidate {
@@ -1476,14 +1480,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
14761480
(
14771481
BuiltinCandidate { has_nested: false }
14781482
| DiscriminantKindCandidate
1479-
| PointeeCandidate,
1483+
| PointeeCandidate
1484+
| ConstDropCandidate,
14801485
_,
14811486
) => true,
14821487
(
14831488
_,
14841489
BuiltinCandidate { has_nested: false }
14851490
| DiscriminantKindCandidate
1486-
| PointeeCandidate,
1491+
| PointeeCandidate
1492+
| ConstDropCandidate,
14871493
) => false,
14881494

14891495
(ParamCandidate(other), ParamCandidate(victim)) => {

compiler/rustc_ty_utils/src/instance.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,8 @@ fn resolve_associated_item<'tcx>(
386386
| traits::ImplSource::TraitAlias(..)
387387
| traits::ImplSource::DiscriminantKind(..)
388388
| traits::ImplSource::Pointee(..)
389-
| traits::ImplSource::TraitUpcasting(_) => None,
389+
| traits::ImplSource::TraitUpcasting(_)
390+
| traits::ImplSource::ConstDrop(_) => None,
390391
})
391392
}
392393

src/test/ui/rfc-2632-const-trait-impl/const-drop.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,57 @@ const fn b() -> u8 {
2323

2424
const C: u8 = b();
2525

26+
macro_rules! implements_const_drop {
27+
($($exp:expr),*$(,)?) => {
28+
$(
29+
const _: () = a($exp);
30+
)*
31+
}
32+
}
33+
34+
#[allow(dead_code)]
35+
mod t {
36+
pub struct Foo;
37+
pub enum Bar { A }
38+
pub fn foo() {}
39+
pub struct ConstDrop;
40+
41+
impl const Drop for ConstDrop {
42+
fn drop(&mut self) {}
43+
}
44+
45+
pub struct HasConstDrop(pub ConstDrop);
46+
pub struct TrivialFields(pub u8, pub i8, pub usize, pub isize);
47+
}
48+
49+
use t::*;
50+
51+
implements_const_drop! {
52+
1u8,
53+
2,
54+
3.0,
55+
Foo,
56+
Bar::A,
57+
foo,
58+
ConstDrop,
59+
HasConstDrop(ConstDrop),
60+
TrivialFields(1, 2, 3, 4),
61+
&1,
62+
&1 as *const i32,
63+
}
64+
2665
fn main() {
66+
struct HasDropGlue(Box<u8>);
67+
struct HasDropImpl;
68+
impl Drop for HasDropImpl {
69+
fn drop(&mut self) {
70+
println!("not trivial drop");
71+
}
72+
}
73+
74+
// These types should pass because ~const in a non-const context should have no effect.
75+
a(HasDropGlue(Box::new(0)));
76+
a(HasDropImpl);
77+
2778
assert_eq!(C, 2);
2879
}

0 commit comments

Comments
 (0)