Use trait select logic instead of query

This commit is contained in:
Deadbeef 2021-09-02 10:59:53 +00:00
parent f0a52128ee
commit 1ca83c6451
No known key found for this signature in database
GPG Key ID: 027DF9338862ADDD
5 changed files with 100 additions and 31 deletions

View File

@ -988,14 +988,12 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
let mut err_span = self.span;
// Check to see if the type of this place can ever have a drop impl. If not, this
// `Drop` terminator is frivolous.
let ty_needs_drop = dropped_place
.ty(self.body, self.tcx)
.ty
.needs_non_const_drop(self.tcx, self.param_env);
let ty_needs_non_const_drop = qualifs::NeedsNonConstDrop::in_any_value_of_ty(
self.ccx,
dropped_place.ty(self.body, self.tcx).ty,
);
if !ty_needs_drop {
if !ty_needs_non_const_drop {
return;
}

View File

@ -3,10 +3,14 @@
//! See the `Qualif` trait for more info.
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
use rustc_span::DUMMY_SP;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::{
self, ImplSource, Obligation, ObligationCause, SelectionContext,
};
use super::ConstCx;
@ -108,7 +112,28 @@ impl Qualif for NeedsNonConstDrop {
}
fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
ty.needs_drop(cx.tcx, cx.param_env)
let trait_ref = ty::TraitRef {
def_id: cx.tcx.require_lang_item(hir::LangItem::Drop, None),
substs: cx.tcx.mk_substs_trait(ty, &[]),
};
let obligation = Obligation::new(
ObligationCause::dummy(),
cx.param_env,
ty::Binder::dummy(ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::ConstIfConst,
}),
);
let implsrc = cx.tcx.infer_ctxt().enter(|infcx| {
let mut selcx = SelectionContext::with_constness(&infcx, hir::Constness::Const);
selcx.select(&obligation)
});
match implsrc {
Ok(Some(ImplSource::ConstDrop(_)))
| Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => false,
_ => true,
}
}
fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool {

View File

@ -283,6 +283,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if self.is_in_const_context {
self.assemble_const_drop_candidates(obligation, &mut candidates)?;
} else {
debug!("passing ~const Drop bound; in non-const context");
// `~const Drop` when we are not in a const context has no effect.
candidates.vec.push(ConstDropCandidate)
}
@ -821,6 +822,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let mut stack: Vec<(Ty<'tcx>, usize)> = vec![(obligation.self_ty().skip_binder(), 0)];
while let Some((ty, depth)) = stack.pop() {
let mut noreturn = false;
self.check_recursion_depth(depth, obligation)?;
let mut copy_candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
let mut copy_obligation =
@ -836,8 +839,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let copy_conditions = self.copy_clone_conditions(&copy_obligation);
self.assemble_builtin_bound_candidates(copy_conditions, &mut copy_candidates);
if !copy_candidates.vec.is_empty() {
continue;
noreturn = true;
}
debug!(?copy_candidates.vec, "assemble_const_drop_candidates - copy");
match ty.kind() {
ty::Int(_)
@ -857,22 +861,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
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| {
self.assemble_candidates_from_impls(
&obligation.with(obligation.predicate.map_bound(|mut pred| {
pred.trait_ref.substs = self.tcx().mk_substs_trait(ty, &[]);
pred
})),
&mut set,
);
stack.extend(def.all_fields().map(|f| (f.ty(self.tcx(), subst), depth + 1)));
debug!(?set.vec, "assemble_const_drop_candidates - ty::Adt");
if set.vec.into_iter().any(|candidate| {
if let SelectionCandidate::ImplCandidate(did) = candidate {
matches!(self.tcx().impl_constness(*did), hir::Constness::NotConst)
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)));
}) {
if !noreturn {
// has non-const Drop
return Ok(());
}
debug!("not returning");
}
}
@ -903,8 +913,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::Infer(_)
| ty::Placeholder(_)
| ty::Projection(..)
| ty::Param(..) => return Ok(()),
| ty::Param(..) => {
if !noreturn {
return Ok(());
}
debug!("not returning");
}
}
debug!(?stack, "assemble_const_drop_candidates - in loop");
}
// all types have passed.
candidates.vec.push(ConstDropCandidate);

View File

@ -16,16 +16,19 @@ impl const Drop for ConstImplWithDropGlue {
fn drop(&mut self) {}
}
const fn check<T: ~const Drop>() {}
const fn check<T: ~const Drop>(_: T) {}
macro_rules! check_all {
($($T:ty),*$(,)?) => {$(
const _: () = check::<$T>();
($($exp:expr),*$(,)?) => {$(
const _: () = check($exp);
)*};
}
check_all! {
ConstImplWithDropGlue,
NonTrivialDrop,
//~^ ERROR the trait bound
ConstImplWithDropGlue(NonTrivialDrop),
//~^ ERROR the trait bound
}
fn main() {}

View File

@ -0,0 +1,27 @@
error[E0277]: the trait bound `NonTrivialDrop: Drop` is not satisfied
--> $DIR/const-drop-fail.rs:28:5
|
LL | NonTrivialDrop,
| ^^^^^^^^^^^^^^ the trait `Drop` is not implemented for `NonTrivialDrop`
|
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:19: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:30:5
|
LL | ConstImplWithDropGlue(NonTrivialDrop),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Drop` is not implemented for `ConstImplWithDropGlue`
|
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:19:19
|
LL | const fn check<T: ~const Drop>(_: T) {}
| ^^^^^^^^^^^ required by this bound in `check`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.