diff options
| author | Deadbeef <ent3rm4n@gmail.com> | 2021-09-01 16:34:28 +0000 |
|---|---|---|
| committer | Deadbeef <ent3rm4n@gmail.com> | 2021-09-09 05:21:31 +0000 |
| commit | a13b13ff46b2d669f0d7a8e024938366fb4a3281 (patch) | |
| tree | b0eb25d07e25a9fcbf522e3d9f523a8784662643 /compiler/rustc_trait_selection/src | |
| parent | 894ce921a091cb9252fd9d72f1c97b3996e3501c (diff) | |
| download | rust-a13b13ff46b2d669f0d7a8e024938366fb4a3281.tar.gz rust-a13b13ff46b2d669f0d7a8e024938366fb4a3281.zip | |
Const drop selection candidates
Diffstat (limited to 'compiler/rustc_trait_selection/src')
4 files changed, 138 insertions, 20 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 7038f16a2c9..49109247663 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1477,7 +1477,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( } super::ImplSource::AutoImpl(..) | super::ImplSource::Builtin(..) - | super::ImplSource::TraitUpcasting(_) => { + | super::ImplSource::TraitUpcasting(_) + | super::ImplSource::ConstDrop(_) => { // These traits have no associated types. selcx.tcx().sess.delay_span_bug( obligation.cause.span, @@ -1549,7 +1550,8 @@ fn confirm_select_candidate<'cx, 'tcx>( | super::ImplSource::Param(..) | super::ImplSource::Builtin(..) | super::ImplSource::TraitUpcasting(_) - | super::ImplSource::TraitAlias(..) => { + | super::ImplSource::TraitAlias(..) + | super::ImplSource::ConstDrop(_) => { // we don't create Select candidates with this kind of resolution span_bug!( obligation.cause.span, diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index e18828fec3f..ffaef566cd5 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -8,7 +8,7 @@ use rustc_hir as hir; use rustc_infer::traits::{Obligation, SelectionError, TraitObligation}; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, TypeFoldable}; +use rustc_middle::ty::{self, Ty, TypeFoldable}; use rustc_target::spec::abi::Abi; use crate::traits::coherence::Conflict; @@ -277,6 +277,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates); } else if lang_items.unsize_trait() == Some(def_id) { self.assemble_candidates_for_unsizing(obligation, &mut candidates); + } else if lang_items.drop_trait() == Some(def_id) + && obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst + { + if self.is_in_const_context { + self.assemble_const_drop_candidates(obligation, &mut candidates)?; + } else { + // `~const Drop` when we are not in a const context has no effect. + candidates.vec.push(ConstDropCandidate) + } } else { if lang_items.clone_trait() == Some(def_id) { // Same builtin conditions as `Copy`, i.e., every type which has builtin support @@ -803,4 +812,103 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } } + + fn assemble_const_drop_candidates( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) -> Result<(), SelectionError<'tcx>> { + let mut stack: Vec<(Ty<'tcx>, usize)> = vec![(obligation.self_ty().skip_binder(), 0)]; + + while let Some((ty, depth)) = stack.pop() { + self.check_recursion_depth(depth, obligation)?; + let mut copy_candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false }; + let mut copy_obligation = + obligation.with(obligation.predicate.rebind(ty::TraitPredicate { + trait_ref: ty::TraitRef { + def_id: self.tcx().require_lang_item(hir::LangItem::Copy, None), + substs: self.tcx().mk_substs_trait(ty, &[]), + }, + constness: ty::BoundConstness::NotConst, + })); + copy_obligation.recursion_depth = depth + 1; + self.assemble_candidates_from_impls(©_obligation, &mut copy_candidates); + let copy_conditions = self.copy_clone_conditions(©_obligation); + self.assemble_builtin_bound_candidates(copy_conditions, &mut copy_candidates); + if !copy_candidates.vec.is_empty() { + continue; + } + + match ty.kind() { + ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Infer(ty::IntVar(_)) + | ty::Infer(ty::FloatVar(_)) + | ty::FnPtr(_) + | ty::Never + | ty::Ref(..) + | ty::FnDef(..) + | ty::RawPtr(_) + | ty::Bool + | ty::Char + | ty::Str + | ty::Foreign(_) => {} // Do nothing. These types satisfy `const Drop`. + + ty::Adt(def, subst) => { + let mut set = SelectionCandidateSet { vec: Vec::new(), ambiguous: false }; + self.assemble_candidates_from_impls(obligation, &mut set); + if set + .vec + .into_iter() + .find(|candidate| { + if let SelectionCandidate::ImplCandidate(did) = candidate { + matches!(self.tcx().impl_constness(*did), hir::Constness::NotConst) + } else { + false + } + }) + .is_none() + { + // could not find a const impl for Drop, iterate over its fields. + stack + .extend(def.all_fields().map(|f| (f.ty(self.tcx(), subst), depth + 1))); + } + } + + ty::Array(ty, _) => stack.push((ty, depth + 1)), + + ty::Tuple(_) => stack.extend(ty.tuple_fields().map(|t| (t, depth + 1))), + + ty::Closure(_, substs) => { + stack.extend(substs.as_closure().upvar_tys().map(|t| (t, depth + 1))) + } + + ty::Generator(_, substs, _) => { + let substs = substs.as_generator(); + stack.extend(substs.upvar_tys().map(|t| (t, depth + 1))); + stack.push((substs.witness(), depth + 1)); + } + + ty::GeneratorWitness(tys) => stack.extend( + self.tcx().erase_late_bound_regions(*tys).iter().map(|t| (t, depth + 1)), + ), + + ty::Slice(ty) => stack.push((ty, depth + 1)), + + ty::Opaque(..) + | ty::Dynamic(..) + | ty::Error(_) + | ty::Bound(..) + | ty::Infer(_) + | ty::Placeholder(_) + | ty::Projection(..) + | ty::Param(..) => return Ok(()), + } + } + // all types have passed. + candidates.vec.push(ConstDropCandidate); + + Ok(()) + } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 6fae8173985..3b6555de912 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -28,7 +28,7 @@ use crate::traits::TraitNotObjectSafe; use crate::traits::VtblSegment; use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation}; use crate::traits::{ - ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData, + ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData, ImplSourceConstDropData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData, ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData, ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, @@ -124,6 +124,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?; Ok(ImplSource::TraitUpcasting(data)) } + + ConstDropCandidate => Ok(ImplSource::ConstDrop(ImplSourceConstDropData)), } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 22013fb79cf..777e4ffc080 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1038,19 +1038,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1); } - /// Checks that the recursion limit has not been exceeded. - /// - /// The weird return type of this function allows it to be used with the `try` (`?`) - /// operator within certain functions. - fn check_recursion_limit<T: Display + TypeFoldable<'tcx>, V: Display + TypeFoldable<'tcx>>( + fn check_recursion_depth<T: Display + TypeFoldable<'tcx>>( &self, - obligation: &Obligation<'tcx, T>, - error_obligation: &Obligation<'tcx, V>, + depth: usize, + error_obligation: &Obligation<'tcx, T>, ) -> Result<(), OverflowError> { - if !self.infcx.tcx.recursion_limit().value_within_limit(obligation.recursion_depth) { + if !self.infcx.tcx.recursion_limit().value_within_limit(depth) { match self.query_mode { TraitQueryMode::Standard => { - self.infcx().report_overflow_error(error_obligation, true); + self.infcx.report_overflow_error(error_obligation, true); } TraitQueryMode::Canonical => { return Err(OverflowError); @@ -1060,6 +1056,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(()) } + /// Checks that the recursion limit has not been exceeded. + /// + /// The weird return type of this function allows it to be used with the `try` (`?`) + /// operator within certain functions. + fn check_recursion_limit<T: Display + TypeFoldable<'tcx>, V: Display + TypeFoldable<'tcx>>( + &self, + obligation: &Obligation<'tcx, T>, + error_obligation: &Obligation<'tcx, V>, + ) -> Result<(), OverflowError> { + self.check_recursion_depth(obligation.recursion_depth, error_obligation) + } + fn in_task<OP, R>(&mut self, op: OP) -> (R, DepNodeIndex) where OP: FnOnce(&mut Self) -> R, @@ -1079,10 +1087,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tcx = self.tcx(); // Respect const trait obligations if self.is_trait_predicate_const(obligation.predicate.skip_binder()) { - if Some(obligation.predicate.skip_binder().trait_ref.def_id) - != tcx.lang_items().sized_trait() - // const Sized bounds are skipped - { match candidate { // const impl ImplCandidate(def_id) @@ -1097,12 +1101,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // generator, this will raise error in other places // or ignore error with const_async_blocks feature GeneratorCandidate => {} + ConstDropCandidate => {} _ => { // reject all other types of candidates return Err(Unimplemented); } } - } } // Treat negative impls as unimplemented, and reservation impls as ambiguity. if let ImplCandidate(def_id) = candidate { @@ -1476,14 +1480,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ( BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate - | PointeeCandidate, + | PointeeCandidate + | ConstDropCandidate, _, ) => true, ( _, BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate - | PointeeCandidate, + | PointeeCandidate + | ConstDropCandidate, ) => false, (ParamCandidate(other), ParamCandidate(victim)) => { |
