From aaaad5b46bd90047fce43672d7848c6c75ceea35 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Tue, 21 Dec 2021 13:23:59 +0800 Subject: [PATCH] Fix bad caching of `~const Drop` bounds --- compiler/rustc_middle/src/ty/mod.rs | 9 ++++++ .../src/traits/select/mod.rs | 6 ++-- .../rfc-2632-const-trait-impl/issue-92111.rs | 29 +++++++++++++++++++ 3 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/rfc-2632-const-trait-impl/issue-92111.rs diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f5a4a4ae24c46..37d99766da9d2 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -734,6 +734,15 @@ pub struct TraitPredicate<'tcx> { pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>; impl<'tcx> TraitPredicate<'tcx> { + pub fn remap_constness(&mut self, tcx: TyCtxt<'tcx>, param_env: &mut ParamEnv<'tcx>) { + if unlikely!(Some(self.trait_ref.def_id) == tcx.lang_items().drop_trait()) { + // remap without changing constness of this predicate. + // this is because `T: ~const Drop` has a different meaning to `T: Drop` + param_env.remap_constness_with(self.constness) + } else { + *param_env = param_env.with_constness(self.constness.and(param_env.constness())) + } + } pub fn def_id(self) -> DefId { self.trait_ref.def_id } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 85016a701f3b1..fa88c8ee37015 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -730,7 +730,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut param_env = obligation.param_env; fresh_trait_pred = fresh_trait_pred.map_bound(|mut pred| { - param_env = param_env.with_constness(pred.constness.and(param_env.constness())); + pred.remap_constness(self.tcx(), &mut param_env); pred }); @@ -1269,7 +1269,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } let tcx = self.tcx(); let mut pred = cache_fresh_trait_pred.skip_binder(); - param_env = param_env.with_constness(pred.constness.and(param_env.constness())); + pred.remap_constness(tcx, &mut param_env); if self.can_use_global_caches(param_env) { if let Some(res) = tcx.selection_cache.get(¶m_env.and(pred), tcx) { @@ -1322,7 +1322,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tcx = self.tcx(); let mut pred = cache_fresh_trait_pred.skip_binder(); - param_env = param_env.with_constness(pred.constness.and(param_env.constness())); + pred.remap_constness(tcx, &mut param_env); if !self.can_cache_candidate(&candidate) { debug!(?pred, ?candidate, "insert_candidate_cache - candidate is not cacheable"); diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-92111.rs b/src/test/ui/rfc-2632-const-trait-impl/issue-92111.rs new file mode 100644 index 0000000000000..d30f4edd4b25c --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/issue-92111.rs @@ -0,0 +1,29 @@ +// Regression test for #92111. +// +// The issue was that we normalize trait bounds before caching +// results of selection. Checking that `impl NoDrop for S` requires +// checking `S: !Drop` because it cannot overlap with the blanket +// impl. Then we save the (unsatisfied) result from checking `S: Drop`. +// Then the call to `a` checks whether `S: ~const Drop` but we normalize +// it to `S: Drop` which the cache claims to be unsatisfied. +// +// check-pass + +#![feature(const_trait_impl)] +#![feature(const_fn_trait_bound)] + +pub trait Tr {} + +#[allow(drop_bounds)] +impl Tr for T {} + +#[derive(Debug)] +pub struct S(i32); + +impl Tr for S {} + +const fn a(t: T) {} + +fn main() { + a(S(0)); +}