|
8 | 8 | use rustc_hir as hir; |
9 | 9 | use rustc_infer::traits::{Obligation, SelectionError, TraitObligation}; |
10 | 10 | use rustc_middle::ty::print::with_no_trimmed_paths; |
11 | | -use rustc_middle::ty::{self, TypeFoldable}; |
| 11 | +use rustc_middle::ty::{self, Ty, TypeFoldable}; |
12 | 12 | use rustc_target::spec::abi::Abi; |
13 | 13 |
|
14 | 14 | use crate::traits::coherence::Conflict; |
@@ -277,6 +277,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { |
277 | 277 | self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates); |
278 | 278 | } else if lang_items.unsize_trait() == Some(def_id) { |
279 | 279 | 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 | + } |
280 | 289 | } else { |
281 | 290 | if lang_items.clone_trait() == Some(def_id) { |
282 | 291 | // Same builtin conditions as `Copy`, i.e., every type which has builtin support |
@@ -803,4 +812,103 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { |
803 | 812 | } |
804 | 813 | } |
805 | 814 | } |
| 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(©_obligation, &mut copy_candidates); |
| 836 | + let copy_conditions = self.copy_clone_conditions(©_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 | + } |
806 | 914 | } |
0 commit comments