Skip to content

Commit 3ee7e2b

Browse files
committed
introduce infcx.at(..).dropck_outlives(..) operaton [VIC]
Backed by a canonicalized query. This computes all the types/regions that need to be live when the destructor runs (i.e., that the dtor may access).
1 parent 01d0dc8 commit 3ee7e2b

File tree

15 files changed

+583
-297
lines changed

15 files changed

+583
-297
lines changed

src/librustc/ich/impls_ty.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -818,12 +818,6 @@ impl_stable_hash_for!(struct ty::Destructor {
818818
did
819819
});
820820

821-
impl_stable_hash_for!(struct ty::DtorckConstraint<'tcx> {
822-
outlives,
823-
dtorck_types
824-
});
825-
826-
827821
impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::CrateVariancesMap {
828822
fn hash_stable<W: StableHasherResult>(&self,
829823
hcx: &mut StableHashingContext<'gcx>,
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use infer::at::At;
12+
use infer::canonical::{Canonical, Canonicalize, QueryResult};
13+
use infer::InferOk;
14+
use std::iter::FromIterator;
15+
use ty::{self, CanonicalIntern, Ty, TyCtxt};
16+
use ty::subst::Kind;
17+
use std::rc::Rc;
18+
19+
pub type CanonicalTyGoal<'tcx> = Canonical<ty::ParamEnvAnd<'tcx, Ty<'tcx>>>;
20+
21+
impl<'cx, 'gcx, 'tcx> At<'cx, 'gcx, 'tcx> {
22+
/// Given a type `ty` of some value being dropped, computes a set
23+
/// of "kinds" (types, regions) that must be outlive the execution
24+
/// of the destructor. These basically correspond to data that the
25+
/// destructor might access. This is used during regionck to
26+
/// impose "outlives" constraints on any lifetimes referenced
27+
/// within.
28+
///
29+
/// The rules here are given by the "dropck" RFCs, notably [#1238]
30+
/// and [#1327]. This is a fixed-point computation, where we
31+
/// explore all the data that will be dropped (transitively) when
32+
/// a value of type `ty` is dropped. For each type T that will be
33+
/// dropped and which has a destructor, we must assume that all
34+
/// the types/regions of T are live during the destructor, unless
35+
/// they are marked with a special attribute (`#[may_dangle]`).
36+
///
37+
/// [#1238]: https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md
38+
/// [#1327]: https://github.com/rust-lang/rfcs/blob/master/text/1327-dropck-param-eyepatch.md
39+
pub fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec<Kind<'tcx>>> {
40+
let tcx = self.infcx.tcx;
41+
let gcx = tcx.global_tcx();
42+
let (c_ty, orig_values) = self.infcx.canonicalize_query(&self.param_env.and(ty));
43+
let span = self.cause.span;
44+
match &gcx.dropck_outlives(c_ty) {
45+
Ok(result) if result.is_proven() => {
46+
match self.infcx.instantiate_query_result(
47+
self.cause,
48+
self.param_env,
49+
&orig_values,
50+
result,
51+
) {
52+
Ok(InferOk {
53+
value: DropckOutlivesResult { kinds, overflows },
54+
obligations,
55+
}) => {
56+
for overflow_ty in overflows.into_iter().take(1) {
57+
let mut err = struct_span_err!(
58+
tcx.sess,
59+
span,
60+
E0320,
61+
"overflow while adding drop-check rules for {}",
62+
self.infcx.resolve_type_vars_if_possible(&ty),
63+
);
64+
err.note(&format!("overflowed on {}", overflow_ty));
65+
err.emit();
66+
}
67+
68+
return InferOk {
69+
value: kinds,
70+
obligations,
71+
};
72+
}
73+
74+
Err(_) => { /* fallthrough to error-handling code below */ }
75+
}
76+
}
77+
78+
_ => { /* fallthrough to error-handling code below */ }
79+
}
80+
81+
// Errors and ambiuity in dropck occur in two cases:
82+
// - unresolved inference variables at the end of typeck
83+
// - non well-formed types where projections cannot be resolved
84+
// Either of these should hvae created an error before.
85+
tcx.sess
86+
.delay_span_bug(span, "dtorck encountered internal error");
87+
return InferOk {
88+
value: vec![],
89+
obligations: vec![],
90+
};
91+
}
92+
}
93+
94+
#[derive(Clone, Debug)]
95+
pub struct DropckOutlivesResult<'tcx> {
96+
pub kinds: Vec<Kind<'tcx>>,
97+
pub overflows: Vec<Ty<'tcx>>,
98+
}
99+
100+
/// A set of constraints that need to be satisfied in order for
101+
/// a type to be valid for destruction.
102+
#[derive(Clone, Debug)]
103+
pub struct DtorckConstraint<'tcx> {
104+
/// Types that are required to be alive in order for this
105+
/// type to be valid for destruction.
106+
pub outlives: Vec<ty::subst::Kind<'tcx>>,
107+
108+
/// Types that could not be resolved: projections and params.
109+
pub dtorck_types: Vec<Ty<'tcx>>,
110+
111+
/// If, during the computation of the dtorck constraint, we
112+
/// overflow, that gets recorded here. The caller is expected to
113+
/// report an error.
114+
pub overflows: Vec<Ty<'tcx>>,
115+
}
116+
117+
impl<'tcx> DtorckConstraint<'tcx> {
118+
pub fn empty() -> DtorckConstraint<'tcx> {
119+
DtorckConstraint {
120+
outlives: vec![],
121+
dtorck_types: vec![],
122+
overflows: vec![],
123+
}
124+
}
125+
}
126+
127+
impl<'tcx> FromIterator<DtorckConstraint<'tcx>> for DtorckConstraint<'tcx> {
128+
fn from_iter<I: IntoIterator<Item = DtorckConstraint<'tcx>>>(iter: I) -> Self {
129+
let mut result = Self::empty();
130+
131+
for DtorckConstraint {
132+
outlives,
133+
dtorck_types,
134+
overflows,
135+
} in iter
136+
{
137+
result.outlives.extend(outlives);
138+
result.dtorck_types.extend(dtorck_types);
139+
result.overflows.extend(overflows);
140+
}
141+
142+
result
143+
}
144+
}
145+
impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for ty::ParamEnvAnd<'tcx, Ty<'tcx>> {
146+
type Canonicalized = &'gcx CanonicalTyGoal<'gcx>;
147+
148+
fn intern(gcx: TyCtxt<'_, 'gcx, 'gcx>, value: Canonical<Self::Lifted>) -> Self::Canonicalized {
149+
value.intern_into(gcx)
150+
}
151+
}
152+
153+
BraceStructTypeFoldableImpl! {
154+
impl<'tcx> TypeFoldable<'tcx> for DropckOutlivesResult<'tcx> {
155+
kinds, overflows
156+
}
157+
}
158+
159+
BraceStructLiftImpl! {
160+
impl<'a, 'tcx> Lift<'tcx> for DropckOutlivesResult<'a> {
161+
type Lifted = DropckOutlivesResult<'tcx>;
162+
kinds, overflows
163+
}
164+
}
165+
166+
impl_stable_hash_for!(struct DropckOutlivesResult<'tcx> {
167+
kinds, overflows
168+
});
169+
170+
impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for QueryResult<'tcx, DropckOutlivesResult<'tcx>> {
171+
// we ought to intern this, but I'm too lazy just now
172+
type Canonicalized = Rc<Canonical<QueryResult<'gcx, DropckOutlivesResult<'gcx>>>>;
173+
174+
fn intern(_gcx: TyCtxt<'_, 'gcx, 'gcx>, value: Canonical<Self::Lifted>) -> Self::Canonicalized {
175+
Rc::new(value)
176+
}
177+
}
178+
179+
impl_stable_hash_for!(struct DtorckConstraint<'tcx> {
180+
outlives,
181+
dtorck_types,
182+
overflows
183+
});

src/librustc/traits/query/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
//! The providers for the queries defined here can be found in
1616
//! `librustc_traits`.
1717
18+
pub mod dropck_outlives;
1819
pub mod normalize;
1920

2021
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]

src/librustc/ty/context.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ use ty::subst::{Kind, Substs};
3535
use ty::ReprOptions;
3636
use ty::Instance;
3737
use traits;
38+
use traits::query::dropck_outlives::CanonicalTyGoal;
3839
use traits::query::normalize::CanonicalProjectionGoal;
3940
use ty::{self, Ty, TypeAndMut};
4041
use ty::{TyS, TypeVariants, Slice};
@@ -107,6 +108,7 @@ pub struct GlobalArenas<'tcx> {
107108
/// miri allocations
108109
const_allocs: TypedArena<interpret::Allocation>,
109110

111+
canonical_ty_goal_arena: TypedArena<CanonicalTyGoal<'tcx>>,
110112
canonical_projection_goal_arena: TypedArena<CanonicalProjectionGoal<'tcx>>,
111113
}
112114

@@ -122,6 +124,7 @@ impl<'tcx> GlobalArenas<'tcx> {
122124
tables: TypedArena::new(),
123125
const_allocs: TypedArena::new(),
124126
canonical_projection_goal_arena: TypedArena::new(),
127+
canonical_ty_goal_arena: TypedArena::new(),
125128
}
126129
}
127130
}
@@ -892,6 +895,11 @@ pub struct GlobalCtxt<'tcx> {
892895

893896
output_filenames: Arc<OutputFilenames>,
894897

898+
/// HashSet used to canonicalize interned canonical types for the
899+
/// `dropck_outlives` query. Each new unique instance is allocated
900+
/// in an arena for use as a query key.
901+
canonical_ty_goal_set: RefCell<FxHashSet<Interned<'tcx, CanonicalTyGoal<'tcx>>>>,
902+
895903
/// HashSet used to canonicalize interned canonical projection
896904
/// goals. Each new unique instance is allocated in an arena for
897905
/// use as a query key.
@@ -1215,6 +1223,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
12151223
on_disk_query_result_cache,
12161224
types: common_types,
12171225
canonical_projection_goal_set: RefCell::new(FxHashSet()),
1226+
canonical_ty_goal_set: RefCell::new(FxHashSet()),
12181227
trait_map,
12191228
export_map: resolutions.export_map.into_iter().map(|(k, v)| {
12201229
(k, Rc::new(v))
@@ -1755,6 +1764,26 @@ impl<'tcx> Borrow<RegionKind> for Interned<'tcx, RegionKind> {
17551764
}
17561765
}
17571766

1767+
impl<'tcx> Borrow<CanonicalTyGoal<'tcx>> for Interned<'tcx, CanonicalTyGoal<'tcx>> {
1768+
fn borrow<'a>(&'a self) -> &'a CanonicalTyGoal<'tcx> {
1769+
&self.0
1770+
}
1771+
}
1772+
1773+
impl<'tcx> PartialEq for Interned<'tcx, CanonicalTyGoal<'tcx>> {
1774+
fn eq(&self, other: &Self) -> bool {
1775+
self.0 == other.0
1776+
}
1777+
}
1778+
1779+
impl<'tcx> Eq for Interned<'tcx, CanonicalTyGoal<'tcx>> { }
1780+
1781+
impl<'tcx> Hash for Interned<'tcx, CanonicalTyGoal<'tcx>> {
1782+
fn hash<H: Hasher>(&self, s: &mut H) {
1783+
self.0.hash(s)
1784+
}
1785+
}
1786+
17581787
impl<'tcx> Borrow<CanonicalProjectionGoal<'tcx>> for Interned<'tcx, CanonicalProjectionGoal<'tcx>> {
17591788
fn borrow<'a>(&'a self) -> &'a CanonicalProjectionGoal<'tcx> {
17601789
&self.0
@@ -2457,6 +2486,20 @@ where
24572486
fn intern_into(self, gcx: TyCtxt<'_, 'gcx, '_>) -> &'gcx Self;
24582487
}
24592488

2489+
impl<'gcx> CanonicalIntern<'gcx> for CanonicalTyGoal<'gcx> {
2490+
fn arena(gcx: TyCtxt<'_, 'gcx, '_>) -> &'gcx TypedArena<Self> {
2491+
&gcx.global_arenas.canonical_ty_goal_arena
2492+
}
2493+
2494+
fn set<'cx>(gcx: TyCtxt<'cx, 'gcx, '_>) -> &'cx RefCell<FxHashSet<Interned<'gcx, Self>>> {
2495+
&gcx.canonical_ty_goal_set
2496+
}
2497+
2498+
fn intern_into(self, gcx: TyCtxt<'_, 'gcx, '_>) -> &'gcx Self {
2499+
intern_into_impl(self, gcx)
2500+
}
2501+
}
2502+
24602503
impl<'gcx> CanonicalIntern<'gcx> for CanonicalProjectionGoal<'gcx> {
24612504
fn arena(gcx: TyCtxt<'_, 'gcx, '_>) -> &'gcx TypedArena<Self> {
24622505
&gcx.global_arenas.canonical_projection_goal_arena

src/librustc/ty/maps/config.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::normalize_projection_ty<'tcx> {
6060
}
6161
}
6262

63+
impl<'tcx> QueryDescription<'tcx> for queries::dropck_outlives<'tcx> {
64+
fn describe(_tcx: TyCtxt, goal: &'tcx Canonical<ParamEnvAnd<'tcx, Ty<'tcx>>>) -> String {
65+
format!("computing dropck types for `{:?}`", goal)
66+
}
67+
}
68+
6369
impl<'tcx> QueryDescription<'tcx> for queries::is_copy_raw<'tcx> {
6470
fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String {
6571
format!("computing whether `{}` is `Copy`", env.value)

src/librustc/ty/maps/keys.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,13 @@ impl<'tcx> Key for &'tcx Canonical<ParamEnvAnd<'tcx, ty::ProjectionTy<'tcx>>> {
170170
DUMMY_SP
171171
}
172172
}
173+
174+
impl<'tcx> Key for &'tcx Canonical<ParamEnvAnd<'tcx, Ty<'tcx>>> {
175+
fn map_crate(&self) -> CrateNum {
176+
LOCAL_CRATE
177+
}
178+
179+
fn default_span(&self, _tcx: TyCtxt) -> Span {
180+
DUMMY_SP
181+
}
182+
}

src/librustc/ty/maps/mod.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use session::{CompileResult, CrateDisambiguator};
3434
use session::config::OutputFilenames;
3535
use traits::Vtable;
3636
use traits::query::NoSolution;
37+
use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
3738
use traits::query::normalize::NormalizationResult;
3839
use traits::specialization_graph;
3940
use ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
@@ -112,7 +113,9 @@ define_maps! { <'tcx>
112113
[] fn adt_def: AdtDefOfItem(DefId) -> &'tcx ty::AdtDef,
113114
[] fn adt_destructor: AdtDestructor(DefId) -> Option<ty::Destructor>,
114115
[] fn adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>],
115-
[] fn adt_dtorck_constraint: DtorckConstraint(DefId) -> ty::DtorckConstraint<'tcx>,
116+
[] fn adt_dtorck_constraint: DtorckConstraint(
117+
DefId
118+
) -> Result<DtorckConstraint<'tcx>, NoSolution>,
116119

117120
/// True if this is a const fn
118121
[] fn is_const_fn: IsConstFn(DefId) -> bool,
@@ -372,6 +375,11 @@ define_maps! { <'tcx>
372375
&'tcx Canonical<ParamEnvAnd<'tcx, ty::ProjectionTy<'tcx>>>
373376
) -> Result<Rc<Canonical<QueryResult<'tcx, NormalizationResult<'tcx>>>>, NoSolution>,
374377

378+
/// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead.
379+
[] fn dropck_outlives: normalize_ty_node(
380+
&'tcx Canonical<ParamEnvAnd<'tcx, Ty<'tcx>>>
381+
) -> Result<Rc<Canonical<QueryResult<'tcx, DropckOutlivesResult<'tcx>>>>, NoSolution>,
382+
375383
[] fn substitute_normalize_and_test_predicates:
376384
substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool,
377385

@@ -519,7 +527,7 @@ fn output_filenames_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
519527
fn vtable_methods_node<'tcx>(trait_ref: ty::PolyTraitRef<'tcx>) -> DepConstructor<'tcx> {
520528
DepConstructor::VtableMethods{ trait_ref }
521529
}
522-
fn normalize_ty_node<'tcx>(_: Ty<'tcx>) -> DepConstructor<'tcx> {
530+
fn normalize_ty_node<'tcx, T>(_: T) -> DepConstructor<'tcx> {
523531
DepConstructor::NormalizeTy
524532
}
525533

src/librustc/ty/maps/values.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,6 @@ impl<'tcx> Value<'tcx> for Ty<'tcx> {
3535
}
3636
}
3737

38-
impl<'tcx> Value<'tcx> for ty::DtorckConstraint<'tcx> {
39-
fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
40-
Self::empty()
41-
}
42-
}
43-
4438
impl<'tcx> Value<'tcx> for ty::SymbolName {
4539
fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
4640
ty::SymbolName { name: Symbol::intern("<error>").as_str() }

0 commit comments

Comments
 (0)