diff options
| author | bors <bors@rust-lang.org> | 2022-01-24 08:05:37 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-01-24 08:05:37 +0000 |
| commit | ef119d704d87a05435ea97ef4161529142313a9b (patch) | |
| tree | 79f04c5b12b95c3b6bab52e108640bf8d131e12b /compiler/rustc_const_eval/src | |
| parent | 42313dd29b3edb0ab453a0d43d12876ec7e48ce0 (diff) | |
| parent | b7e443397471062e5681ecefb6638577cefb9571 (diff) | |
| download | rust-ef119d704d87a05435ea97ef4161529142313a9b.tar.gz rust-ef119d704d87a05435ea97ef4161529142313a9b.zip | |
Auto merge of #93028 - compiler-errors:const_drop_bounds, r=fee1-dead
Check `const Drop` impls considering `~const` Bounds This PR adds logic to trait selection to account for `~const` bounds in custom `impl const Drop` for types, elaborates the `const Drop` check in `rustc_const_eval` to check those bounds, and steals some drop linting fixes from #92922, thanks `@DrMeepster.` r? `@fee1-dead` `@oli-obk` <sup>(edit: guess I can't request review from two people, lol)</sup> since each of you wrote and reviewed #88558, respectively. Since the logic here is more complicated than what existed, it's possible that this is a perf regression. But it works correctly with tests, and that makes me happy. Fixes #92881
Diffstat (limited to 'compiler/rustc_const_eval/src')
| -rw-r--r-- | compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs | 60 |
1 files changed, 39 insertions, 21 deletions
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index cf939aaa73f..91610b15eb9 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -4,11 +4,12 @@ use rustc_errors::ErrorReported; use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::traits::TraitEngine; use rustc_middle::mir::*; use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty}; use rustc_span::DUMMY_SP; use rustc_trait_selection::traits::{ - self, ImplSource, Obligation, ObligationCause, SelectionContext, + self, FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, }; use super::ConstCx; @@ -145,15 +146,10 @@ impl Qualif for NeedsNonConstDrop { qualifs.needs_non_const_drop } - fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, mut ty: Ty<'tcx>) -> bool { - // Avoid selecting for simple cases. - match ty::util::needs_drop_components(ty, &cx.tcx.data_layout).as_deref() { - Ok([]) => return false, - Err(ty::util::AlwaysRequiresDrop) => return true, - // If we've got a single component, select with that - // to increase the chance that we hit the selection cache. - Ok([t]) => ty = t, - Ok([..]) => {} + fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { + // Avoid selecting for simple cases, such as builtin types. + if ty::util::is_trivially_const_drop(ty) { + return false; } let Some(drop_trait) = cx.tcx.lang_items().drop_trait() else { @@ -161,28 +157,50 @@ impl Qualif for NeedsNonConstDrop { // without having the lang item present. return false; }; - let trait_ref = - ty::TraitRef { def_id: drop_trait, substs: cx.tcx.mk_substs_trait(ty, &[]) }; + let obligation = Obligation::new( ObligationCause::dummy(), cx.param_env, ty::Binder::dummy(ty::TraitPredicate { - trait_ref, + trait_ref: ty::TraitRef { + def_id: drop_trait, + substs: cx.tcx.mk_substs_trait(ty, &[]), + }, constness: ty::BoundConstness::ConstIfConst, polarity: ty::ImplPolarity::Positive, }), ); - let implsrc = cx.tcx.infer_ctxt().enter(|infcx| { + cx.tcx.infer_ctxt().enter(|infcx| { let mut selcx = SelectionContext::new(&infcx); - selcx.select(&obligation) - }); - !matches!( - implsrc, - Ok(Some( + let Some(impl_src) = selcx.select(&obligation).ok().flatten() else { + // If we couldn't select a const drop candidate, then it's bad + return true; + }; + + if !matches!( + impl_src, ImplSource::ConstDrop(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst) - )) - ) + ) { + // If our const drop candidate is not ConstDrop or implied by the param env, + // then it's bad + return true; + } + + if impl_src.borrow_nested_obligations().is_empty() { + return false; + } + + // If we successfully found one, then select all of the predicates + // implied by our const drop impl. + let mut fcx = FulfillmentContext::new(); + for nested in impl_src.nested_obligations() { + fcx.register_predicate_obligation(&infcx, nested); + } + + // If we had any errors, then it's bad + !fcx.select_all_or_error(&infcx).is_empty() + }) } fn in_adt_inherently<'tcx>( |
