Skip to content

Commit f629baf

Browse files
committed
Move magic traits queries to rustc::traits::drop.
1 parent 86ec4b5 commit f629baf

File tree

7 files changed

+211
-203
lines changed

7 files changed

+211
-203
lines changed

src/librustc/traits/drop.rs

+202
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
//! Miscellaneous type-system utilities that are too small to deserve their own modules.
2+
3+
use crate::middle::lang_items;
4+
use crate::traits::{self, ObligationCause};
5+
use crate::ty::util::NeedsDrop;
6+
use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
7+
8+
use rustc_hir as hir;
9+
use rustc_span::DUMMY_SP;
10+
11+
#[derive(Clone)]
12+
pub enum CopyImplementationError<'tcx> {
13+
InfrigingFields(Vec<&'tcx ty::FieldDef>),
14+
NotAnAdt,
15+
HasDestructor,
16+
}
17+
18+
pub fn can_type_implement_copy(
19+
tcx: TyCtxt<'tcx>,
20+
param_env: ty::ParamEnv<'tcx>,
21+
self_type: Ty<'tcx>,
22+
) -> Result<(), CopyImplementationError<'tcx>> {
23+
// FIXME: (@jroesch) float this code up
24+
tcx.infer_ctxt().enter(|infcx| {
25+
let (adt, substs) = match self_type.kind {
26+
// These types used to have a builtin impl.
27+
// Now libcore provides that impl.
28+
ty::Uint(_)
29+
| ty::Int(_)
30+
| ty::Bool
31+
| ty::Float(_)
32+
| ty::Char
33+
| ty::RawPtr(..)
34+
| ty::Never
35+
| ty::Ref(_, _, hir::Mutability::Not) => return Ok(()),
36+
37+
ty::Adt(adt, substs) => (adt, substs),
38+
39+
_ => return Err(CopyImplementationError::NotAnAdt),
40+
};
41+
42+
let mut infringing = Vec::new();
43+
for variant in &adt.variants {
44+
for field in &variant.fields {
45+
let ty = field.ty(tcx, substs);
46+
if ty.references_error() {
47+
continue;
48+
}
49+
let span = tcx.def_span(field.did);
50+
let cause = ObligationCause { span, ..ObligationCause::dummy() };
51+
let ctx = traits::FulfillmentContext::new();
52+
match traits::fully_normalize(&infcx, ctx, cause, param_env, &ty) {
53+
Ok(ty) => {
54+
if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
55+
infringing.push(field);
56+
}
57+
}
58+
Err(errors) => {
59+
infcx.report_fulfillment_errors(&errors, None, false);
60+
}
61+
};
62+
}
63+
}
64+
if !infringing.is_empty() {
65+
return Err(CopyImplementationError::InfrigingFields(infringing));
66+
}
67+
if adt.has_dtor(tcx) {
68+
return Err(CopyImplementationError::HasDestructor);
69+
}
70+
71+
Ok(())
72+
})
73+
}
74+
75+
fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
76+
is_item_raw(tcx, query, lang_items::CopyTraitLangItem)
77+
}
78+
79+
fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
80+
is_item_raw(tcx, query, lang_items::SizedTraitLangItem)
81+
}
82+
83+
fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
84+
is_item_raw(tcx, query, lang_items::FreezeTraitLangItem)
85+
}
86+
87+
fn is_item_raw<'tcx>(
88+
tcx: TyCtxt<'tcx>,
89+
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
90+
item: lang_items::LangItem,
91+
) -> bool {
92+
let (param_env, ty) = query.into_parts();
93+
let trait_def_id = tcx.require_lang_item(item, None);
94+
tcx.infer_ctxt().enter(|infcx| {
95+
traits::type_known_to_meet_bound_modulo_regions(
96+
&infcx,
97+
param_env,
98+
ty,
99+
trait_def_id,
100+
DUMMY_SP,
101+
)
102+
})
103+
}
104+
105+
fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> NeedsDrop {
106+
let (param_env, ty) = query.into_parts();
107+
108+
let needs_drop = |ty: Ty<'tcx>| -> bool { tcx.needs_drop_raw(param_env.and(ty)).0 };
109+
110+
assert!(!ty.needs_infer());
111+
112+
NeedsDrop(match ty.kind {
113+
// Fast-path for primitive types
114+
ty::Infer(ty::FreshIntTy(_))
115+
| ty::Infer(ty::FreshFloatTy(_))
116+
| ty::Bool
117+
| ty::Int(_)
118+
| ty::Uint(_)
119+
| ty::Float(_)
120+
| ty::Never
121+
| ty::FnDef(..)
122+
| ty::FnPtr(_)
123+
| ty::Char
124+
| ty::GeneratorWitness(..)
125+
| ty::RawPtr(_)
126+
| ty::Ref(..)
127+
| ty::Str => false,
128+
129+
// Foreign types can never have destructors
130+
ty::Foreign(..) => false,
131+
132+
// `ManuallyDrop` doesn't have a destructor regardless of field types.
133+
ty::Adt(def, _) if Some(def.did) == tcx.lang_items().manually_drop() => false,
134+
135+
// Issue #22536: We first query `is_copy_modulo_regions`. It sees a
136+
// normalized version of the type, and therefore will definitely
137+
// know whether the type implements Copy (and thus needs no
138+
// cleanup/drop/zeroing) ...
139+
_ if ty.is_copy_modulo_regions(tcx, param_env, DUMMY_SP) => false,
140+
141+
// ... (issue #22536 continued) but as an optimization, still use
142+
// prior logic of asking for the structural "may drop".
143+
144+
// FIXME(#22815): Note that this is a conservative heuristic;
145+
// it may report that the type "may drop" when actual type does
146+
// not actually have a destructor associated with it. But since
147+
// the type absolutely did not have the `Copy` bound attached
148+
// (see above), it is sound to treat it as having a destructor.
149+
150+
// User destructors are the only way to have concrete drop types.
151+
ty::Adt(def, _) if def.has_dtor(tcx) => true,
152+
153+
// Can refer to a type which may drop.
154+
// FIXME(eddyb) check this against a ParamEnv.
155+
ty::Dynamic(..)
156+
| ty::Projection(..)
157+
| ty::Param(_)
158+
| ty::Bound(..)
159+
| ty::Placeholder(..)
160+
| ty::Opaque(..)
161+
| ty::Infer(_)
162+
| ty::Error => true,
163+
164+
ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
165+
166+
// Zero-length arrays never contain anything to drop.
167+
ty::Array(_, len) if len.try_eval_usize(tcx, param_env) == Some(0) => false,
168+
169+
// Structural recursion.
170+
ty::Array(ty, _) | ty::Slice(ty) => needs_drop(ty),
171+
172+
ty::Closure(def_id, ref substs) => {
173+
substs.as_closure().upvar_tys(def_id, tcx).any(needs_drop)
174+
}
175+
176+
// Pessimistically assume that all generators will require destructors
177+
// as we don't know if a destructor is a noop or not until after the MIR
178+
// state transformation pass
179+
ty::Generator(..) => true,
180+
181+
ty::Tuple(..) => ty.tuple_fields().any(needs_drop),
182+
183+
// unions don't have destructors because of the child types,
184+
// only if they manually implement `Drop` (handled above).
185+
ty::Adt(def, _) if def.is_union() => false,
186+
187+
ty::Adt(def, substs) => def
188+
.variants
189+
.iter()
190+
.any(|variant| variant.fields.iter().any(|field| needs_drop(field.ty(tcx, substs)))),
191+
})
192+
}
193+
194+
pub fn provide(providers: &mut ty::query::Providers<'_>) {
195+
*providers = ty::query::Providers {
196+
is_copy_raw,
197+
is_sized_raw,
198+
is_freeze_raw,
199+
needs_drop_raw,
200+
..*providers
201+
};
202+
}

src/librustc/traits/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pub mod auto_trait;
77
mod chalk_fulfill;
88
pub mod codegen;
99
mod coherence;
10+
pub mod drop;
1011
mod engine;
1112
pub mod error_reporting;
1213
mod fulfill;
@@ -1243,6 +1244,7 @@ impl<'tcx> TraitObligation<'tcx> {
12431244
}
12441245

12451246
pub fn provide(providers: &mut ty::query::Providers<'_>) {
1247+
drop::provide(providers);
12461248
*providers = ty::query::Providers {
12471249
is_object_safe: object_safety::is_object_safe_provider,
12481250
specialization_graph_of: specialize::specialization_graph_provider,

src/librustc/ty/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -3318,7 +3318,6 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
33183318
context::provide(providers);
33193319
erase_regions::provide(providers);
33203320
layout::provide(providers);
3321-
util::provide(providers);
33223321
constness::provide(providers);
33233322
*providers = ty::query::Providers {
33243323
asyncness,

0 commit comments

Comments
 (0)