Skip to content

Commit ca87d24

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 3a50b41 commit ca87d24

File tree

17 files changed

+560
-301
lines changed

17 files changed

+560
-301
lines changed

src/librustc/dep_graph/dep_node.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
7070
use std::fmt;
7171
use std::hash::Hash;
7272
use syntax_pos::symbol::InternedString;
73-
use traits::query::CanonicalProjectionGoal;
73+
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal};
7474
use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty};
7575
use ty::subst::Substs;
7676

@@ -637,6 +637,8 @@ define_dep_nodes!( <'tcx>
637637
[input] OutputFilenames,
638638
[anon] NormalizeTy,
639639
[] NormalizeProjectionTy(CanonicalProjectionGoal<'tcx>),
640+
[] NormalizeTyAfterErasingRegions(ParamEnvAnd<'tcx, Ty<'tcx>>),
641+
[] DropckOutlives(CanonicalTyGoal<'tcx>),
640642

641643
[] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) },
642644

src/librustc/ich/impls_ty.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,12 +1017,6 @@ impl_stable_hash_for!(struct ty::Destructor {
10171017
did
10181018
});
10191019

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

src/librustc/traits/query/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@
1616
//! `librustc_traits`.
1717
1818
use infer::canonical::Canonical;
19-
use ty;
19+
use ty::{self, Ty};
2020

21+
pub mod dropck_outlives;
2122
pub mod normalize;
2223

2324
pub type CanonicalProjectionGoal<'tcx> =
2425
Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::ProjectionTy<'tcx>>>;
2526

27+
pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>;
28+
2629
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
2730
pub struct NoSolution;
2831

src/librustc/ty/context.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ pub struct GlobalArenas<'tcx> {
106106
tables: TypedArena<ty::TypeckTables<'tcx>>,
107107
/// miri allocations
108108
const_allocs: TypedArena<interpret::Allocation>,
109-
110109
}
111110

112111
impl<'tcx> GlobalArenas<'tcx> {

src/librustc/ty/maps/config.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
use dep_graph::SerializedDepNodeIndex;
1212
use hir::def_id::{CrateNum, DefId, DefIndex};
1313
use mir::interpret::{GlobalId};
14-
use traits::query::CanonicalProjectionGoal;
14+
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal};
1515
use ty::{self, Ty, TyCtxt};
1616
use ty::subst::Substs;
1717
use ty::maps::queries;
@@ -61,6 +61,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::normalize_projection_ty<'tcx> {
6161
}
6262
}
6363

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

src/librustc/ty/maps/keys.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
//! Defines the set of legal keys that can be used in queries.
1212
1313
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex};
14-
use traits::query::CanonicalProjectionGoal;
14+
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal};
1515
use ty::{self, Ty, TyCtxt};
1616
use ty::subst::Substs;
1717
use ty::fast_reject::SimplifiedType;
@@ -181,3 +181,13 @@ impl<'tcx> Key for CanonicalProjectionGoal<'tcx> {
181181
DUMMY_SP
182182
}
183183
}
184+
185+
impl<'tcx> Key for CanonicalTyGoal<'tcx> {
186+
fn map_crate(&self) -> CrateNum {
187+
LOCAL_CRATE
188+
}
189+
190+
fn default_span(&self, _tcx: TyCtxt) -> Span {
191+
DUMMY_SP
192+
}
193+
}

src/librustc/ty/maps/mod.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ use mir::interpret::{GlobalId};
3434
use session::{CompileResult, CrateDisambiguator};
3535
use session::config::OutputFilenames;
3636
use traits::Vtable;
37-
use traits::query::{CanonicalProjectionGoal, NoSolution};
37+
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal, NoSolution};
38+
use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
3839
use traits::query::normalize::NormalizationResult;
3940
use traits::specialization_graph;
4041
use ty::{self, CrateInherentImpls, Ty, TyCtxt};
@@ -114,7 +115,9 @@ define_maps! { <'tcx>
114115
[] fn adt_def: AdtDefOfItem(DefId) -> &'tcx ty::AdtDef,
115116
[] fn adt_destructor: AdtDestructor(DefId) -> Option<ty::Destructor>,
116117
[] fn adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>],
117-
[] fn adt_dtorck_constraint: DtorckConstraint(DefId) -> ty::DtorckConstraint<'tcx>,
118+
[] fn adt_dtorck_constraint: DtorckConstraint(
119+
DefId
120+
) -> Result<DtorckConstraint<'tcx>, NoSolution>,
118121

119122
/// True if this is a const fn
120123
[] fn is_const_fn: IsConstFn(DefId) -> bool,
@@ -391,6 +394,14 @@ define_maps! { <'tcx>
391394
NoSolution,
392395
>,
393396

397+
/// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead.
398+
[] fn dropck_outlives: DropckOutlives(
399+
CanonicalTyGoal<'tcx>
400+
) -> Result<
401+
Lrc<Canonical<'tcx, QueryResult<'tcx, DropckOutlivesResult<'tcx>>>>,
402+
NoSolution,
403+
>,
404+
394405
[] fn substitute_normalize_and_test_predicates:
395406
substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool,
396407

src/librustc/ty/maps/plumbing.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
774774
DepKind::EraseRegionsTy |
775775
DepKind::NormalizeTy |
776776
DepKind::NormalizeProjectionTy |
777+
DepKind::DropckOutlives |
777778
DepKind::SubstituteNormalizeAndTestPredicates |
778779
DepKind::InstanceDefSizeEstimate |
779780

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)