Skip to content

Commit ef119d7

Browse files
committed
Auto merge of rust-lang#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 rust-lang#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 rust-lang#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 rust-lang#92881
2 parents 42313dd + b7e4433 commit ef119d7

File tree

13 files changed

+378
-238
lines changed

13 files changed

+378
-238
lines changed

compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs

+39-21
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
55
use rustc_errors::ErrorReported;
66
use rustc_infer::infer::TyCtxtInferExt;
7+
use rustc_infer::traits::TraitEngine;
78
use rustc_middle::mir::*;
89
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
910
use rustc_span::DUMMY_SP;
1011
use rustc_trait_selection::traits::{
11-
self, ImplSource, Obligation, ObligationCause, SelectionContext,
12+
self, FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext,
1213
};
1314

1415
use super::ConstCx;
@@ -145,44 +146,61 @@ impl Qualif for NeedsNonConstDrop {
145146
qualifs.needs_non_const_drop
146147
}
147148

148-
fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, mut ty: Ty<'tcx>) -> bool {
149-
// Avoid selecting for simple cases.
150-
match ty::util::needs_drop_components(ty, &cx.tcx.data_layout).as_deref() {
151-
Ok([]) => return false,
152-
Err(ty::util::AlwaysRequiresDrop) => return true,
153-
// If we've got a single component, select with that
154-
// to increase the chance that we hit the selection cache.
155-
Ok([t]) => ty = t,
156-
Ok([..]) => {}
149+
fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
150+
// Avoid selecting for simple cases, such as builtin types.
151+
if ty::util::is_trivially_const_drop(ty) {
152+
return false;
157153
}
158154

159155
let Some(drop_trait) = cx.tcx.lang_items().drop_trait() else {
160156
// there is no way to define a type that needs non-const drop
161157
// without having the lang item present.
162158
return false;
163159
};
164-
let trait_ref =
165-
ty::TraitRef { def_id: drop_trait, substs: cx.tcx.mk_substs_trait(ty, &[]) };
160+
166161
let obligation = Obligation::new(
167162
ObligationCause::dummy(),
168163
cx.param_env,
169164
ty::Binder::dummy(ty::TraitPredicate {
170-
trait_ref,
165+
trait_ref: ty::TraitRef {
166+
def_id: drop_trait,
167+
substs: cx.tcx.mk_substs_trait(ty, &[]),
168+
},
171169
constness: ty::BoundConstness::ConstIfConst,
172170
polarity: ty::ImplPolarity::Positive,
173171
}),
174172
);
175173

176-
let implsrc = cx.tcx.infer_ctxt().enter(|infcx| {
174+
cx.tcx.infer_ctxt().enter(|infcx| {
177175
let mut selcx = SelectionContext::new(&infcx);
178-
selcx.select(&obligation)
179-
});
180-
!matches!(
181-
implsrc,
182-
Ok(Some(
176+
let Some(impl_src) = selcx.select(&obligation).ok().flatten() else {
177+
// If we couldn't select a const drop candidate, then it's bad
178+
return true;
179+
};
180+
181+
if !matches!(
182+
impl_src,
183183
ImplSource::ConstDrop(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
184-
))
185-
)
184+
) {
185+
// If our const drop candidate is not ConstDrop or implied by the param env,
186+
// then it's bad
187+
return true;
188+
}
189+
190+
if impl_src.borrow_nested_obligations().is_empty() {
191+
return false;
192+
}
193+
194+
// If we successfully found one, then select all of the predicates
195+
// implied by our const drop impl.
196+
let mut fcx = FulfillmentContext::new();
197+
for nested in impl_src.nested_obligations() {
198+
fcx.register_predicate_obligation(&infcx, nested);
199+
}
200+
201+
// If we had any errors, then it's bad
202+
!fcx.select_all_or_error(&infcx).is_empty()
203+
})
186204
}
187205

188206
fn in_adt_inherently<'tcx>(

compiler/rustc_middle/src/traits/mod.rs

+12-10
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ pub enum ImplSource<'tcx, N> {
566566
TraitAlias(ImplSourceTraitAliasData<'tcx, N>),
567567

568568
/// ImplSource for a `const Drop` implementation.
569-
ConstDrop(ImplSourceConstDropData),
569+
ConstDrop(ImplSourceConstDropData<N>),
570570
}
571571

572572
impl<'tcx, N> ImplSource<'tcx, N> {
@@ -581,10 +581,10 @@ impl<'tcx, N> ImplSource<'tcx, N> {
581581
ImplSource::Object(d) => d.nested,
582582
ImplSource::FnPointer(d) => d.nested,
583583
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
584-
| ImplSource::Pointee(ImplSourcePointeeData)
585-
| ImplSource::ConstDrop(ImplSourceConstDropData) => Vec::new(),
584+
| ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(),
586585
ImplSource::TraitAlias(d) => d.nested,
587586
ImplSource::TraitUpcasting(d) => d.nested,
587+
ImplSource::ConstDrop(i) => i.nested,
588588
}
589589
}
590590

@@ -599,10 +599,10 @@ impl<'tcx, N> ImplSource<'tcx, N> {
599599
ImplSource::Object(d) => &d.nested,
600600
ImplSource::FnPointer(d) => &d.nested,
601601
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
602-
| ImplSource::Pointee(ImplSourcePointeeData)
603-
| ImplSource::ConstDrop(ImplSourceConstDropData) => &[],
602+
| ImplSource::Pointee(ImplSourcePointeeData) => &[],
604603
ImplSource::TraitAlias(d) => &d.nested,
605604
ImplSource::TraitUpcasting(d) => &d.nested,
605+
ImplSource::ConstDrop(i) => &i.nested,
606606
}
607607
}
608608

@@ -661,9 +661,9 @@ impl<'tcx, N> ImplSource<'tcx, N> {
661661
nested: d.nested.into_iter().map(f).collect(),
662662
})
663663
}
664-
ImplSource::ConstDrop(ImplSourceConstDropData) => {
665-
ImplSource::ConstDrop(ImplSourceConstDropData)
666-
}
664+
ImplSource::ConstDrop(i) => ImplSource::ConstDrop(ImplSourceConstDropData {
665+
nested: i.nested.into_iter().map(f).collect(),
666+
}),
667667
}
668668
}
669669
}
@@ -755,8 +755,10 @@ pub struct ImplSourceDiscriminantKindData;
755755
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
756756
pub struct ImplSourcePointeeData;
757757

758-
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
759-
pub struct ImplSourceConstDropData;
758+
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
759+
pub struct ImplSourceConstDropData<N> {
760+
pub nested: Vec<N>,
761+
}
760762

761763
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
762764
pub struct ImplSourceTraitAliasData<'tcx, N> {

compiler/rustc_middle/src/traits/select.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,8 @@ pub enum SelectionCandidate<'tcx> {
146146

147147
BuiltinUnsizeCandidate,
148148

149-
/// Implementation of `const Drop`.
150-
ConstDropCandidate,
149+
/// Implementation of `const Drop`, optionally from a custom `impl const Drop`.
150+
ConstDropCandidate(Option<DefId>),
151151
}
152152

153153
/// The result of trait evaluation. The order is important

compiler/rustc_middle/src/traits/structural_impls.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,17 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitAliasData<'tcx,
120120
}
121121
}
122122

123+
impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceConstDropData<N> {
124+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125+
write!(f, "ImplSourceConstDropData(nested={:?})", self.nested)
126+
}
127+
}
128+
123129
///////////////////////////////////////////////////////////////////////////
124130
// Lift implementations
125131

126132
TrivialTypeFoldableAndLiftImpls! {
127133
super::IfExpressionCause,
128134
super::ImplSourceDiscriminantKindData,
129135
super::ImplSourcePointeeData,
130-
super::ImplSourceConstDropData,
131136
}

compiler/rustc_middle/src/ty/util.rs

+36
Original file line numberDiff line numberDiff line change
@@ -1041,6 +1041,42 @@ pub fn needs_drop_components<'tcx>(
10411041
}
10421042
}
10431043

1044+
pub fn is_trivially_const_drop<'tcx>(ty: Ty<'tcx>) -> bool {
1045+
match *ty.kind() {
1046+
ty::Bool
1047+
| ty::Char
1048+
| ty::Int(_)
1049+
| ty::Uint(_)
1050+
| ty::Float(_)
1051+
| ty::Infer(ty::IntVar(_))
1052+
| ty::Infer(ty::FloatVar(_))
1053+
| ty::Str
1054+
| ty::RawPtr(_)
1055+
| ty::Ref(..)
1056+
| ty::FnDef(..)
1057+
| ty::FnPtr(_)
1058+
| ty::Never
1059+
| ty::Foreign(_) => true,
1060+
1061+
ty::Opaque(..)
1062+
| ty::Dynamic(..)
1063+
| ty::Error(_)
1064+
| ty::Bound(..)
1065+
| ty::Param(_)
1066+
| ty::Placeholder(_)
1067+
| ty::Projection(_)
1068+
| ty::Infer(_) => false,
1069+
1070+
// Not trivial because they have components, and instead of looking inside,
1071+
// we'll just perform trait selection.
1072+
ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(_) | ty::Adt(..) => false,
1073+
1074+
ty::Array(ty, _) | ty::Slice(ty) => is_trivially_const_drop(ty),
1075+
1076+
ty::Tuple(tys) => tys.iter().all(|ty| is_trivially_const_drop(ty.expect_ty())),
1077+
}
1078+
}
1079+
10441080
// Does the equivalent of
10451081
// ```
10461082
// let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>();

0 commit comments

Comments
 (0)