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).
This commit is contained in:
parent
3a50b41da4
commit
ca87d24467
@ -70,7 +70,7 @@ use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
use syntax_pos::symbol::InternedString;
|
||||
use traits::query::CanonicalProjectionGoal;
|
||||
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal};
|
||||
use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty};
|
||||
use ty::subst::Substs;
|
||||
|
||||
@ -637,6 +637,8 @@ define_dep_nodes!( <'tcx>
|
||||
[input] OutputFilenames,
|
||||
[anon] NormalizeTy,
|
||||
[] NormalizeProjectionTy(CanonicalProjectionGoal<'tcx>),
|
||||
[] NormalizeTyAfterErasingRegions(ParamEnvAnd<'tcx, Ty<'tcx>>),
|
||||
[] DropckOutlives(CanonicalTyGoal<'tcx>),
|
||||
|
||||
[] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) },
|
||||
|
||||
|
@ -1017,12 +1017,6 @@ impl_stable_hash_for!(struct ty::Destructor {
|
||||
did
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(struct ty::DtorckConstraint<'tcx> {
|
||||
outlives,
|
||||
dtorck_types
|
||||
});
|
||||
|
||||
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for ty::CrateVariancesMap {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
|
193
src/librustc/traits/query/dropck_outlives.rs
Normal file
193
src/librustc/traits/query/dropck_outlives.rs
Normal file
@ -0,0 +1,193 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use infer::at::At;
|
||||
use infer::canonical::{Canonical, Canonicalize, QueryResult};
|
||||
use infer::InferOk;
|
||||
use std::iter::FromIterator;
|
||||
use traits::query::CanonicalTyGoal;
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::subst::Kind;
|
||||
use std::rc::Rc;
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> At<'cx, 'gcx, 'tcx> {
|
||||
/// Given a type `ty` of some value being dropped, computes a set
|
||||
/// of "kinds" (types, regions) that must be outlive the execution
|
||||
/// of the destructor. These basically correspond to data that the
|
||||
/// destructor might access. This is used during regionck to
|
||||
/// impose "outlives" constraints on any lifetimes referenced
|
||||
/// within.
|
||||
///
|
||||
/// The rules here are given by the "dropck" RFCs, notably [#1238]
|
||||
/// and [#1327]. This is a fixed-point computation, where we
|
||||
/// explore all the data that will be dropped (transitively) when
|
||||
/// a value of type `ty` is dropped. For each type T that will be
|
||||
/// dropped and which has a destructor, we must assume that all
|
||||
/// the types/regions of T are live during the destructor, unless
|
||||
/// they are marked with a special attribute (`#[may_dangle]`).
|
||||
///
|
||||
/// [#1238]: https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md
|
||||
/// [#1327]: https://github.com/rust-lang/rfcs/blob/master/text/1327-dropck-param-eyepatch.md
|
||||
pub fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec<Kind<'tcx>>> {
|
||||
debug!(
|
||||
"dropck_outlives(ty={:?}, param_env={:?})",
|
||||
ty, self.param_env,
|
||||
);
|
||||
|
||||
let tcx = self.infcx.tcx;
|
||||
let gcx = tcx.global_tcx();
|
||||
let (c_ty, orig_values) = self.infcx.canonicalize_query(&self.param_env.and(ty));
|
||||
let span = self.cause.span;
|
||||
match &gcx.dropck_outlives(c_ty) {
|
||||
Ok(result) if result.is_proven() => {
|
||||
match self.infcx.instantiate_query_result(
|
||||
self.cause,
|
||||
self.param_env,
|
||||
&orig_values,
|
||||
result,
|
||||
) {
|
||||
Ok(InferOk {
|
||||
value: DropckOutlivesResult { kinds, overflows },
|
||||
obligations,
|
||||
}) => {
|
||||
for overflow_ty in overflows.into_iter().take(1) {
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
span,
|
||||
E0320,
|
||||
"overflow while adding drop-check rules for {}",
|
||||
self.infcx.resolve_type_vars_if_possible(&ty),
|
||||
);
|
||||
err.note(&format!("overflowed on {}", overflow_ty));
|
||||
err.emit();
|
||||
}
|
||||
|
||||
return InferOk {
|
||||
value: kinds,
|
||||
obligations,
|
||||
};
|
||||
}
|
||||
|
||||
Err(_) => { /* fallthrough to error-handling code below */ }
|
||||
}
|
||||
}
|
||||
|
||||
_ => { /* fallthrough to error-handling code below */ }
|
||||
}
|
||||
|
||||
// Errors and ambiuity in dropck occur in two cases:
|
||||
// - unresolved inference variables at the end of typeck
|
||||
// - non well-formed types where projections cannot be resolved
|
||||
// Either of these should hvae created an error before.
|
||||
tcx.sess
|
||||
.delay_span_bug(span, "dtorck encountered internal error");
|
||||
return InferOk {
|
||||
value: vec![],
|
||||
obligations: vec![],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DropckOutlivesResult<'tcx> {
|
||||
pub kinds: Vec<Kind<'tcx>>,
|
||||
pub overflows: Vec<Ty<'tcx>>,
|
||||
}
|
||||
|
||||
/// A set of constraints that need to be satisfied in order for
|
||||
/// a type to be valid for destruction.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DtorckConstraint<'tcx> {
|
||||
/// Types that are required to be alive in order for this
|
||||
/// type to be valid for destruction.
|
||||
pub outlives: Vec<ty::subst::Kind<'tcx>>,
|
||||
|
||||
/// Types that could not be resolved: projections and params.
|
||||
pub dtorck_types: Vec<Ty<'tcx>>,
|
||||
|
||||
/// If, during the computation of the dtorck constraint, we
|
||||
/// overflow, that gets recorded here. The caller is expected to
|
||||
/// report an error.
|
||||
pub overflows: Vec<Ty<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> DtorckConstraint<'tcx> {
|
||||
pub fn empty() -> DtorckConstraint<'tcx> {
|
||||
DtorckConstraint {
|
||||
outlives: vec![],
|
||||
dtorck_types: vec![],
|
||||
overflows: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> FromIterator<DtorckConstraint<'tcx>> for DtorckConstraint<'tcx> {
|
||||
fn from_iter<I: IntoIterator<Item = DtorckConstraint<'tcx>>>(iter: I) -> Self {
|
||||
let mut result = Self::empty();
|
||||
|
||||
for DtorckConstraint {
|
||||
outlives,
|
||||
dtorck_types,
|
||||
overflows,
|
||||
} in iter
|
||||
{
|
||||
result.outlives.extend(outlives);
|
||||
result.dtorck_types.extend(dtorck_types);
|
||||
result.overflows.extend(overflows);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for ty::ParamEnvAnd<'tcx, Ty<'tcx>> {
|
||||
type Canonicalized = CanonicalTyGoal<'gcx>;
|
||||
|
||||
fn intern(
|
||||
_gcx: TyCtxt<'_, 'gcx, 'gcx>,
|
||||
value: Canonical<'gcx, Self::Lifted>,
|
||||
) -> Self::Canonicalized {
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
BraceStructTypeFoldableImpl! {
|
||||
impl<'tcx> TypeFoldable<'tcx> for DropckOutlivesResult<'tcx> {
|
||||
kinds, overflows
|
||||
}
|
||||
}
|
||||
|
||||
BraceStructLiftImpl! {
|
||||
impl<'a, 'tcx> Lift<'tcx> for DropckOutlivesResult<'a> {
|
||||
type Lifted = DropckOutlivesResult<'tcx>;
|
||||
kinds, overflows
|
||||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(struct DropckOutlivesResult<'tcx> {
|
||||
kinds, overflows
|
||||
});
|
||||
|
||||
impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for QueryResult<'tcx, DropckOutlivesResult<'tcx>> {
|
||||
// we ought to intern this, but I'm too lazy just now
|
||||
type Canonicalized = Rc<Canonical<'gcx, QueryResult<'gcx, DropckOutlivesResult<'gcx>>>>;
|
||||
|
||||
fn intern(
|
||||
_gcx: TyCtxt<'_, 'gcx, 'gcx>,
|
||||
value: Canonical<'gcx, Self::Lifted>,
|
||||
) -> Self::Canonicalized {
|
||||
Rc::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(struct DtorckConstraint<'tcx> {
|
||||
outlives,
|
||||
dtorck_types,
|
||||
overflows
|
||||
});
|
@ -16,13 +16,16 @@
|
||||
//! `librustc_traits`.
|
||||
|
||||
use infer::canonical::Canonical;
|
||||
use ty;
|
||||
use ty::{self, Ty};
|
||||
|
||||
pub mod dropck_outlives;
|
||||
pub mod normalize;
|
||||
|
||||
pub type CanonicalProjectionGoal<'tcx> =
|
||||
Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::ProjectionTy<'tcx>>>;
|
||||
|
||||
pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct NoSolution;
|
||||
|
||||
|
@ -106,7 +106,6 @@ pub struct GlobalArenas<'tcx> {
|
||||
tables: TypedArena<ty::TypeckTables<'tcx>>,
|
||||
/// miri allocations
|
||||
const_allocs: TypedArena<interpret::Allocation>,
|
||||
|
||||
}
|
||||
|
||||
impl<'tcx> GlobalArenas<'tcx> {
|
||||
|
@ -11,7 +11,7 @@
|
||||
use dep_graph::SerializedDepNodeIndex;
|
||||
use hir::def_id::{CrateNum, DefId, DefIndex};
|
||||
use mir::interpret::{GlobalId};
|
||||
use traits::query::CanonicalProjectionGoal;
|
||||
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal};
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::subst::Substs;
|
||||
use ty::maps::queries;
|
||||
@ -61,6 +61,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::normalize_projection_ty<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> QueryDescription<'tcx> for queries::dropck_outlives<'tcx> {
|
||||
fn describe(_tcx: TyCtxt, goal: CanonicalTyGoal<'tcx>) -> String {
|
||||
format!("computing dropck types for `{:?}`", goal)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> QueryDescription<'tcx> for queries::is_copy_raw<'tcx> {
|
||||
fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String {
|
||||
format!("computing whether `{}` is `Copy`", env.value)
|
||||
|
@ -11,7 +11,7 @@
|
||||
//! Defines the set of legal keys that can be used in queries.
|
||||
|
||||
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex};
|
||||
use traits::query::CanonicalProjectionGoal;
|
||||
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal};
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::subst::Substs;
|
||||
use ty::fast_reject::SimplifiedType;
|
||||
@ -181,3 +181,13 @@ impl<'tcx> Key for CanonicalProjectionGoal<'tcx> {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for CanonicalTyGoal<'tcx> {
|
||||
fn map_crate(&self) -> CrateNum {
|
||||
LOCAL_CRATE
|
||||
}
|
||||
|
||||
fn default_span(&self, _tcx: TyCtxt) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,8 @@ use mir::interpret::{GlobalId};
|
||||
use session::{CompileResult, CrateDisambiguator};
|
||||
use session::config::OutputFilenames;
|
||||
use traits::Vtable;
|
||||
use traits::query::{CanonicalProjectionGoal, NoSolution};
|
||||
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal, NoSolution};
|
||||
use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
|
||||
use traits::query::normalize::NormalizationResult;
|
||||
use traits::specialization_graph;
|
||||
use ty::{self, CrateInherentImpls, Ty, TyCtxt};
|
||||
@ -114,7 +115,9 @@ define_maps! { <'tcx>
|
||||
[] fn adt_def: AdtDefOfItem(DefId) -> &'tcx ty::AdtDef,
|
||||
[] fn adt_destructor: AdtDestructor(DefId) -> Option<ty::Destructor>,
|
||||
[] fn adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>],
|
||||
[] fn adt_dtorck_constraint: DtorckConstraint(DefId) -> ty::DtorckConstraint<'tcx>,
|
||||
[] fn adt_dtorck_constraint: DtorckConstraint(
|
||||
DefId
|
||||
) -> Result<DtorckConstraint<'tcx>, NoSolution>,
|
||||
|
||||
/// True if this is a const fn
|
||||
[] fn is_const_fn: IsConstFn(DefId) -> bool,
|
||||
@ -391,6 +394,14 @@ define_maps! { <'tcx>
|
||||
NoSolution,
|
||||
>,
|
||||
|
||||
/// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead.
|
||||
[] fn dropck_outlives: DropckOutlives(
|
||||
CanonicalTyGoal<'tcx>
|
||||
) -> Result<
|
||||
Lrc<Canonical<'tcx, QueryResult<'tcx, DropckOutlivesResult<'tcx>>>>,
|
||||
NoSolution,
|
||||
>,
|
||||
|
||||
[] fn substitute_normalize_and_test_predicates:
|
||||
substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool,
|
||||
|
||||
|
@ -774,6 +774,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
|
||||
DepKind::EraseRegionsTy |
|
||||
DepKind::NormalizeTy |
|
||||
DepKind::NormalizeProjectionTy |
|
||||
DepKind::DropckOutlives |
|
||||
DepKind::SubstituteNormalizeAndTestPredicates |
|
||||
DepKind::InstanceDefSizeEstimate |
|
||||
|
||||
|
@ -35,12 +35,6 @@ impl<'tcx> Value<'tcx> for Ty<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Value<'tcx> for ty::DtorckConstraint<'tcx> {
|
||||
fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
|
||||
Self::empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Value<'tcx> for ty::SymbolName {
|
||||
fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
|
||||
ty::SymbolName { name: Symbol::intern("<error>").as_str() }
|
||||
|
@ -34,15 +34,13 @@ use ty;
|
||||
use ty::subst::{Subst, Substs};
|
||||
use ty::util::{IntTypeExt, Discr};
|
||||
use ty::walk::TypeWalker;
|
||||
use util::common::ErrorReported;
|
||||
use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet};
|
||||
use util::nodemap::{NodeSet, DefIdMap, FxHashMap};
|
||||
|
||||
use serialize::{self, Encodable, Encoder};
|
||||
use std::cell::RefCell;
|
||||
use std::cmp;
|
||||
use std::fmt;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::iter::FromIterator;
|
||||
use std::ops::Deref;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use std::slice;
|
||||
@ -2661,38 +2659,6 @@ fn adt_sized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
result
|
||||
}
|
||||
|
||||
/// Calculates the dtorck constraint for a type.
|
||||
fn adt_dtorck_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
def_id: DefId)
|
||||
-> DtorckConstraint<'tcx> {
|
||||
let def = tcx.adt_def(def_id);
|
||||
let span = tcx.def_span(def_id);
|
||||
debug!("dtorck_constraint: {:?}", def);
|
||||
|
||||
if def.is_phantom_data() {
|
||||
let result = DtorckConstraint {
|
||||
outlives: vec![],
|
||||
dtorck_types: vec![
|
||||
tcx.mk_param_from_def(&tcx.generics_of(def_id).types[0])
|
||||
]
|
||||
};
|
||||
debug!("dtorck_constraint: {:?} => {:?}", def, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
let mut result = def.all_fields()
|
||||
.map(|field| tcx.type_of(field.did))
|
||||
.map(|fty| tcx.dtorck_constraint_for_ty(span, fty, 0, fty))
|
||||
.collect::<Result<DtorckConstraint, ErrorReported>>()
|
||||
.unwrap_or(DtorckConstraint::empty());
|
||||
result.outlives.extend(tcx.destructor_constraints(def));
|
||||
result.dedup();
|
||||
|
||||
debug!("dtorck_constraint: {:?} => {:?}", def, result);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn associated_item_def_ids<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
def_id: DefId)
|
||||
-> Lrc<Vec<DefId>> {
|
||||
@ -2808,7 +2774,6 @@ pub fn provide(providers: &mut ty::maps::Providers) {
|
||||
associated_item,
|
||||
associated_item_def_ids,
|
||||
adt_sized_constraint,
|
||||
adt_dtorck_constraint,
|
||||
def_span,
|
||||
param_env,
|
||||
trait_of_item,
|
||||
@ -2831,49 +2796,6 @@ pub struct CrateInherentImpls {
|
||||
pub inherent_impls: DefIdMap<Lrc<Vec<DefId>>>,
|
||||
}
|
||||
|
||||
/// A set of constraints that need to be satisfied in order for
|
||||
/// a type to be valid for destruction.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DtorckConstraint<'tcx> {
|
||||
/// Types that are required to be alive in order for this
|
||||
/// type to be valid for destruction.
|
||||
pub outlives: Vec<ty::subst::Kind<'tcx>>,
|
||||
/// Types that could not be resolved: projections and params.
|
||||
pub dtorck_types: Vec<Ty<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> FromIterator<DtorckConstraint<'tcx>> for DtorckConstraint<'tcx>
|
||||
{
|
||||
fn from_iter<I: IntoIterator<Item=DtorckConstraint<'tcx>>>(iter: I) -> Self {
|
||||
let mut result = Self::empty();
|
||||
|
||||
for constraint in iter {
|
||||
result.outlives.extend(constraint.outlives);
|
||||
result.dtorck_types.extend(constraint.dtorck_types);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'tcx> DtorckConstraint<'tcx> {
|
||||
fn empty() -> DtorckConstraint<'tcx> {
|
||||
DtorckConstraint {
|
||||
outlives: vec![],
|
||||
dtorck_types: vec![]
|
||||
}
|
||||
}
|
||||
|
||||
fn dedup<'a>(&mut self) {
|
||||
let mut outlives = FxHashSet();
|
||||
let mut dtorck_types = FxHashSet();
|
||||
|
||||
self.outlives.retain(|&val| outlives.replace(val).is_none());
|
||||
self.dtorck_types.retain(|&val| dtorck_types.replace(val).is_none());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
|
||||
pub struct SymbolName {
|
||||
// FIXME: we don't rely on interning or equality here - better have
|
||||
|
@ -19,7 +19,7 @@ use middle::const_val::ConstVal;
|
||||
use traits;
|
||||
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use ty::fold::TypeVisitor;
|
||||
use ty::subst::{Subst, UnpackedKind};
|
||||
use ty::subst::UnpackedKind;
|
||||
use ty::maps::TyCtxtAt;
|
||||
use ty::TypeVariants::*;
|
||||
use ty::layout::Integer;
|
||||
@ -537,99 +537,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
result
|
||||
}
|
||||
|
||||
/// Return a set of constraints that needs to be satisfied in
|
||||
/// order for `ty` to be valid for destruction.
|
||||
pub fn dtorck_constraint_for_ty(self,
|
||||
span: Span,
|
||||
for_ty: Ty<'tcx>,
|
||||
depth: usize,
|
||||
ty: Ty<'tcx>)
|
||||
-> Result<ty::DtorckConstraint<'tcx>, ErrorReported>
|
||||
{
|
||||
debug!("dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})",
|
||||
span, for_ty, depth, ty);
|
||||
|
||||
if depth >= self.sess.recursion_limit.get() {
|
||||
let mut err = struct_span_err!(
|
||||
self.sess, span, E0320,
|
||||
"overflow while adding drop-check rules for {}", for_ty);
|
||||
err.note(&format!("overflowed on {}", ty));
|
||||
err.emit();
|
||||
return Err(ErrorReported);
|
||||
}
|
||||
|
||||
let result = match ty.sty {
|
||||
ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) |
|
||||
ty::TyFloat(_) | ty::TyStr | ty::TyNever | ty::TyForeign(..) |
|
||||
ty::TyRawPtr(..) | ty::TyRef(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) |
|
||||
ty::TyGeneratorWitness(..) => {
|
||||
// these types never have a destructor
|
||||
Ok(ty::DtorckConstraint::empty())
|
||||
}
|
||||
|
||||
ty::TyArray(ety, _) | ty::TySlice(ety) => {
|
||||
// single-element containers, behave like their element
|
||||
self.dtorck_constraint_for_ty(span, for_ty, depth+1, ety)
|
||||
}
|
||||
|
||||
ty::TyTuple(tys, _) => {
|
||||
tys.iter().map(|ty| {
|
||||
self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty)
|
||||
}).collect()
|
||||
}
|
||||
|
||||
ty::TyClosure(def_id, substs) => {
|
||||
substs.upvar_tys(def_id, self).map(|ty| {
|
||||
self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty)
|
||||
}).collect()
|
||||
}
|
||||
|
||||
ty::TyGenerator(def_id, substs, _) => {
|
||||
// Note that the interior types are ignored here.
|
||||
// Any type reachable inside the interior must also be reachable
|
||||
// through the upvars.
|
||||
substs.upvar_tys(def_id, self).map(|ty| {
|
||||
self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty)
|
||||
}).collect()
|
||||
}
|
||||
|
||||
ty::TyAdt(def, substs) => {
|
||||
let ty::DtorckConstraint {
|
||||
dtorck_types, outlives
|
||||
} = self.at(span).adt_dtorck_constraint(def.did);
|
||||
Ok(ty::DtorckConstraint {
|
||||
// FIXME: we can try to recursively `dtorck_constraint_on_ty`
|
||||
// there, but that needs some way to handle cycles.
|
||||
dtorck_types: dtorck_types.subst(self, substs),
|
||||
outlives: outlives.subst(self, substs)
|
||||
})
|
||||
}
|
||||
|
||||
// Objects must be alive in order for their destructor
|
||||
// to be called.
|
||||
ty::TyDynamic(..) => Ok(ty::DtorckConstraint {
|
||||
outlives: vec![ty.into()],
|
||||
dtorck_types: vec![],
|
||||
}),
|
||||
|
||||
// Types that can't be resolved. Pass them forward.
|
||||
ty::TyProjection(..) | ty::TyAnon(..) | ty::TyParam(..) => {
|
||||
Ok(ty::DtorckConstraint {
|
||||
outlives: vec![],
|
||||
dtorck_types: vec![ty],
|
||||
})
|
||||
}
|
||||
|
||||
ty::TyInfer(..) | ty::TyError => {
|
||||
self.sess.delay_span_bug(span, "unresolved type in dtorck");
|
||||
Err(ErrorReported)
|
||||
}
|
||||
};
|
||||
|
||||
debug!("dtorck_constraint_for_ty({:?}) = {:?}", ty, result);
|
||||
result
|
||||
}
|
||||
|
||||
pub fn is_closure(self, def_id: DefId) -> bool {
|
||||
self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr
|
||||
}
|
||||
|
@ -14,13 +14,9 @@ use dataflow::MaybeInitializedPlaces;
|
||||
use dataflow::move_paths::{HasMoveData, MoveData};
|
||||
use rustc::mir::{BasicBlock, Location, Mir};
|
||||
use rustc::mir::Local;
|
||||
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc::traits;
|
||||
use rustc::ty::{Ty, TyCtxt, TypeFoldable};
|
||||
use rustc::infer::InferOk;
|
||||
use rustc::util::common::ErrorReported;
|
||||
use borrow_check::nll::type_check::AtLocation;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use syntax::codemap::DUMMY_SP;
|
||||
use util::liveness::LivenessResults;
|
||||
|
||||
use super::TypeChecker;
|
||||
@ -193,73 +189,34 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo
|
||||
//
|
||||
// For this reason, we avoid calling TypeChecker.normalize, instead doing all normalization
|
||||
// ourselves in one large 'fully_perform_op' callback.
|
||||
let (type_constraints, kind_constraints) = self.cx.fully_perform_op(location.at_self(),
|
||||
|cx| {
|
||||
let kind_constraints = self.cx
|
||||
.fully_perform_op(location.at_self(), |cx| {
|
||||
let span = cx.last_span;
|
||||
|
||||
let tcx = cx.infcx.tcx;
|
||||
let mut selcx = traits::SelectionContext::new(cx.infcx);
|
||||
let cause = cx.misc(cx.last_span);
|
||||
let mut final_obligations = Vec::new();
|
||||
let mut kind_constraints = Vec::new();
|
||||
|
||||
let mut types = vec![(dropped_ty, 0)];
|
||||
let mut final_obligations = Vec::new();
|
||||
let mut type_constraints = Vec::new();
|
||||
let mut kind_constraints = Vec::new();
|
||||
|
||||
let mut known = FxHashSet();
|
||||
|
||||
while let Some((ty, depth)) = types.pop() {
|
||||
let span = DUMMY_SP; // FIXME
|
||||
let result = match tcx.dtorck_constraint_for_ty(span, dropped_ty, depth, ty) {
|
||||
Ok(result) => result,
|
||||
Err(ErrorReported) => {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let ty::DtorckConstraint {
|
||||
outlives,
|
||||
dtorck_types,
|
||||
} = result;
|
||||
|
||||
// All things in the `outlives` array may be touched by
|
||||
// the destructor and must be live at this point.
|
||||
for outlive in outlives {
|
||||
let InferOk {
|
||||
value: kinds,
|
||||
obligations,
|
||||
} = cx.infcx
|
||||
.at(&cx.misc(span), cx.param_env)
|
||||
.dropck_outlives(dropped_ty);
|
||||
for kind in kinds {
|
||||
// All things in the `outlives` array may be touched by
|
||||
// the destructor and must be live at this point.
|
||||
let cause = Cause::DropVar(dropped_local, location);
|
||||
kind_constraints.push((outlive, location, cause));
|
||||
kind_constraints.push((kind, location, cause));
|
||||
}
|
||||
|
||||
// However, there may also be some types that
|
||||
// `dtorck_constraint_for_ty` could not resolve (e.g.,
|
||||
// associated types and parameters). We need to normalize
|
||||
// associated types here and possibly recursively process.
|
||||
for ty in dtorck_types {
|
||||
let traits::Normalized { value: ty, obligations } =
|
||||
traits::normalize(&mut selcx, cx.param_env, cause.clone(), &ty);
|
||||
final_obligations.extend(obligations);
|
||||
|
||||
final_obligations.extend(obligations);
|
||||
|
||||
let ty = cx.infcx.resolve_type_and_region_vars_if_possible(&ty);
|
||||
match ty.sty {
|
||||
ty::TyParam(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
|
||||
let cause = Cause::DropVar(dropped_local, location);
|
||||
type_constraints.push((ty, location, cause));
|
||||
}
|
||||
|
||||
_ => if known.insert(ty) {
|
||||
types.push((ty, depth + 1));
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(InferOk {
|
||||
value: (type_constraints, kind_constraints), obligations: final_obligations
|
||||
Ok(InferOk {
|
||||
value: kind_constraints,
|
||||
obligations: final_obligations,
|
||||
})
|
||||
})
|
||||
}).unwrap();
|
||||
|
||||
for (ty, location, cause) in type_constraints {
|
||||
self.push_type_live_constraint(ty, location, cause);
|
||||
}
|
||||
.unwrap();
|
||||
|
||||
for (kind, location, cause) in kind_constraints {
|
||||
self.push_type_live_constraint(kind, location, cause);
|
||||
|
285
src/librustc_traits/dropck_outlives.rs
Normal file
285
src/librustc_traits/dropck_outlives.rs
Normal file
@ -0,0 +1,285 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use rustc::infer::canonical::{Canonical, QueryResult};
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::traits::{FulfillmentContext, Normalized, ObligationCause};
|
||||
use rustc::traits::query::{CanonicalTyGoal, NoSolution};
|
||||
use rustc::traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
|
||||
use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt};
|
||||
use rustc::ty::subst::Subst;
|
||||
use rustc::util::nodemap::FxHashSet;
|
||||
use std::rc::Rc;
|
||||
use syntax::codemap::{Span, DUMMY_SP};
|
||||
use util;
|
||||
|
||||
crate fn dropck_outlives<'tcx>(
|
||||
tcx: TyCtxt<'_, 'tcx, 'tcx>,
|
||||
goal: CanonicalTyGoal<'tcx>,
|
||||
) -> Result<Rc<Canonical<'tcx, QueryResult<'tcx, DropckOutlivesResult<'tcx>>>>, NoSolution> {
|
||||
debug!("dropck_outlives(goal={:#?})", goal);
|
||||
|
||||
tcx.infer_ctxt().enter(|ref infcx| {
|
||||
let tcx = infcx.tcx;
|
||||
let (
|
||||
ParamEnvAnd {
|
||||
param_env,
|
||||
value: for_ty,
|
||||
},
|
||||
canonical_inference_vars,
|
||||
) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &goal);
|
||||
|
||||
let mut result = DropckOutlivesResult { kinds: vec![], overflows: vec![] };
|
||||
|
||||
// A stack of types left to process. Each round, we pop
|
||||
// something from the stack and invoke
|
||||
// `dtorck_constraint_for_ty`. This may produce new types that
|
||||
// have to be pushed on the stack. This continues until we have explored
|
||||
// all the reachable types from the type `for_ty`.
|
||||
//
|
||||
// Example: Imagine that we have the following code:
|
||||
//
|
||||
// ```rust
|
||||
// struct A {
|
||||
// value: B,
|
||||
// children: Vec<A>,
|
||||
// }
|
||||
//
|
||||
// struct B {
|
||||
// value: u32
|
||||
// }
|
||||
//
|
||||
// fn f() {
|
||||
// let a: A = ...;
|
||||
// ..
|
||||
// } // here, `a` is dropped
|
||||
// ```
|
||||
//
|
||||
// at the point where `a` is dropped, we need to figure out
|
||||
// which types inside of `a` contain region data that may be
|
||||
// accessed by any destructors in `a`. We begin by pushing `A`
|
||||
// onto the stack, as that is the type of `a`. We will then
|
||||
// invoke `dtorck_constraint_for_ty` which will expand `A`
|
||||
// into the types of its fields `(B, Vec<A>)`. These will get
|
||||
// pushed onto the stack. Eventually, expanding `Vec<A>` will
|
||||
// lead to us trying to push `A` a second time -- to prevent
|
||||
// infinite recusion, we notice that `A` was already pushed
|
||||
// once and stop.
|
||||
let mut ty_stack = vec![(for_ty, 0)];
|
||||
|
||||
// Set used to detect infinite recursion.
|
||||
let mut ty_set = FxHashSet();
|
||||
|
||||
let fulfill_cx = &mut FulfillmentContext::new();
|
||||
|
||||
let cause = ObligationCause::dummy();
|
||||
while let Some((ty, depth)) = ty_stack.pop() {
|
||||
let DtorckConstraint {
|
||||
dtorck_types,
|
||||
outlives,
|
||||
overflows,
|
||||
} = dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty)?;
|
||||
|
||||
// "outlives" represent types/regions that may be touched
|
||||
// by a destructor.
|
||||
result.kinds.extend(outlives);
|
||||
result.overflows.extend(overflows);
|
||||
|
||||
// dtorck types are "types that will get dropped but which
|
||||
// do not themselves define a destructor", more or less. We have
|
||||
// to push them onto the stack to be expanded.
|
||||
for ty in dtorck_types {
|
||||
match infcx.at(&cause, param_env).normalize(&ty) {
|
||||
Ok(Normalized {
|
||||
value: ty,
|
||||
obligations,
|
||||
}) => {
|
||||
fulfill_cx.register_predicate_obligations(infcx, obligations);
|
||||
|
||||
debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
|
||||
|
||||
match ty.sty {
|
||||
// All parameters live for the duration of the
|
||||
// function.
|
||||
ty::TyParam(..) => {}
|
||||
|
||||
// A projection that we couldn't resolve - it
|
||||
// might have a destructor.
|
||||
ty::TyProjection(..) | ty::TyAnon(..) => {
|
||||
result.kinds.push(ty.into());
|
||||
}
|
||||
|
||||
_ => {
|
||||
if ty_set.insert(ty) {
|
||||
ty_stack.push((ty, depth + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We don't actually expect to fail to normalize.
|
||||
// That implies a WF error somewhere else.
|
||||
Err(NoSolution) => {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug!("dropck_outlives: result = {:#?}", result);
|
||||
|
||||
util::make_query_response(infcx, canonical_inference_vars, result, fulfill_cx)
|
||||
})
|
||||
}
|
||||
|
||||
/// Return a set of constraints that needs to be satisfied in
|
||||
/// order for `ty` to be valid for destruction.
|
||||
fn dtorck_constraint_for_ty<'a, 'gcx, 'tcx>(
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
span: Span,
|
||||
for_ty: Ty<'tcx>,
|
||||
depth: usize,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Result<DtorckConstraint<'tcx>, NoSolution> {
|
||||
debug!(
|
||||
"dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})",
|
||||
span, for_ty, depth, ty
|
||||
);
|
||||
|
||||
if depth >= tcx.sess.recursion_limit.get() {
|
||||
return Ok(DtorckConstraint {
|
||||
outlives: vec![],
|
||||
dtorck_types: vec![],
|
||||
overflows: vec![ty],
|
||||
});
|
||||
}
|
||||
|
||||
let result = match ty.sty {
|
||||
ty::TyBool
|
||||
| ty::TyChar
|
||||
| ty::TyInt(_)
|
||||
| ty::TyUint(_)
|
||||
| ty::TyFloat(_)
|
||||
| ty::TyStr
|
||||
| ty::TyNever
|
||||
| ty::TyForeign(..)
|
||||
| ty::TyRawPtr(..)
|
||||
| ty::TyRef(..)
|
||||
| ty::TyFnDef(..)
|
||||
| ty::TyFnPtr(_)
|
||||
| ty::TyGeneratorWitness(..) => {
|
||||
// these types never have a destructor
|
||||
Ok(DtorckConstraint::empty())
|
||||
}
|
||||
|
||||
ty::TyArray(ety, _) | ty::TySlice(ety) => {
|
||||
// single-element containers, behave like their element
|
||||
dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ety)
|
||||
}
|
||||
|
||||
ty::TyTuple(tys, _) => tys.iter()
|
||||
.map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty))
|
||||
.collect(),
|
||||
|
||||
ty::TyClosure(def_id, substs) => substs
|
||||
.upvar_tys(def_id, tcx)
|
||||
.map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty))
|
||||
.collect(),
|
||||
|
||||
ty::TyGenerator(def_id, substs, _) => {
|
||||
// Note that the interior types are ignored here.
|
||||
// Any type reachable inside the interior must also be reachable
|
||||
// through the upvars.
|
||||
substs
|
||||
.upvar_tys(def_id, tcx)
|
||||
.map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty))
|
||||
.collect()
|
||||
}
|
||||
|
||||
ty::TyAdt(def, substs) => {
|
||||
let DtorckConstraint {
|
||||
dtorck_types,
|
||||
outlives,
|
||||
overflows,
|
||||
} = tcx.at(span).adt_dtorck_constraint(def.did)?;
|
||||
Ok(DtorckConstraint {
|
||||
// FIXME: we can try to recursively `dtorck_constraint_on_ty`
|
||||
// there, but that needs some way to handle cycles.
|
||||
dtorck_types: dtorck_types.subst(tcx, substs),
|
||||
outlives: outlives.subst(tcx, substs),
|
||||
overflows: overflows.subst(tcx, substs),
|
||||
})
|
||||
}
|
||||
|
||||
// Objects must be alive in order for their destructor
|
||||
// to be called.
|
||||
ty::TyDynamic(..) => Ok(DtorckConstraint {
|
||||
outlives: vec![ty.into()],
|
||||
dtorck_types: vec![],
|
||||
overflows: vec![],
|
||||
}),
|
||||
|
||||
// Types that can't be resolved. Pass them forward.
|
||||
ty::TyProjection(..) | ty::TyAnon(..) | ty::TyParam(..) => Ok(DtorckConstraint {
|
||||
outlives: vec![],
|
||||
dtorck_types: vec![ty],
|
||||
overflows: vec![],
|
||||
}),
|
||||
|
||||
ty::TyInfer(..) | ty::TyError => {
|
||||
// By the time this code runs, all type variables ought to
|
||||
// be fully resolved.
|
||||
Err(NoSolution)
|
||||
}
|
||||
};
|
||||
|
||||
debug!("dtorck_constraint_for_ty({:?}) = {:?}", ty, result);
|
||||
result
|
||||
}
|
||||
|
||||
/// Calculates the dtorck constraint for a type.
|
||||
crate fn adt_dtorck_constraint<'a, 'tcx>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
def_id: DefId,
|
||||
) -> Result<DtorckConstraint<'tcx>, NoSolution> {
|
||||
let def = tcx.adt_def(def_id);
|
||||
let span = tcx.def_span(def_id);
|
||||
debug!("dtorck_constraint: {:?}", def);
|
||||
|
||||
if def.is_phantom_data() {
|
||||
let result = DtorckConstraint {
|
||||
outlives: vec![],
|
||||
dtorck_types: vec![tcx.mk_param_from_def(&tcx.generics_of(def_id).types[0])],
|
||||
overflows: vec![],
|
||||
};
|
||||
debug!("dtorck_constraint: {:?} => {:?}", def, result);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
let mut result = def.all_fields()
|
||||
.map(|field| tcx.type_of(field.did))
|
||||
.map(|fty| dtorck_constraint_for_ty(tcx, span, fty, 0, fty))
|
||||
.collect::<Result<DtorckConstraint, NoSolution>>()?;
|
||||
result.outlives.extend(tcx.destructor_constraints(def));
|
||||
dedup_dtorck_constraint(&mut result);
|
||||
|
||||
debug!("dtorck_constraint: {:?} => {:?}", def, result);
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn dedup_dtorck_constraint<'tcx>(c: &mut DtorckConstraint<'tcx>) {
|
||||
let mut outlives = FxHashSet();
|
||||
let mut dtorck_types = FxHashSet();
|
||||
|
||||
c.outlives.retain(|&val| outlives.replace(val).is_none());
|
||||
c.dtorck_types
|
||||
.retain(|&val| dtorck_types.replace(val).is_none());
|
||||
}
|
@ -24,6 +24,7 @@ extern crate rustc_data_structures;
|
||||
extern crate syntax;
|
||||
extern crate syntax_pos;
|
||||
|
||||
mod dropck_outlives;
|
||||
mod normalize_projection_ty;
|
||||
mod util;
|
||||
|
||||
@ -31,6 +32,8 @@ use rustc::ty::maps::Providers;
|
||||
|
||||
pub fn provide(p: &mut Providers) {
|
||||
*p = Providers {
|
||||
dropck_outlives: dropck_outlives::dropck_outlives,
|
||||
adt_dtorck_constraint: dropck_outlives::adt_dtorck_constraint,
|
||||
normalize_projection_ty: normalize_projection_ty::normalize_projection_ty,
|
||||
..*p
|
||||
};
|
||||
|
@ -18,8 +18,8 @@ use rustc::ty::subst::{Subst, Substs, UnpackedKind};
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::traits::{self, ObligationCause};
|
||||
use util::common::ErrorReported;
|
||||
use util::nodemap::FxHashSet;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
|
||||
/// check_drop_impl confirms that the Drop implementation identified by
|
||||
@ -282,6 +282,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>(
|
||||
rcx: &mut RegionCtxt<'a, 'gcx, 'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
body_id: ast::NodeId,
|
||||
scope: region::Scope)
|
||||
-> Result<(), ErrorReported>
|
||||
{
|
||||
@ -297,46 +298,15 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>(
|
||||
};
|
||||
let parent_scope = rcx.tcx.mk_region(ty::ReScope(parent_scope));
|
||||
let origin = || infer::SubregionOrigin::SafeDestructor(span);
|
||||
|
||||
let ty = rcx.fcx.resolve_type_vars_if_possible(&ty);
|
||||
let for_ty = ty;
|
||||
let mut types = vec![(ty, 0)];
|
||||
let mut known = FxHashSet();
|
||||
while let Some((ty, depth)) = types.pop() {
|
||||
let ty::DtorckConstraint {
|
||||
dtorck_types, outlives
|
||||
} = rcx.tcx.dtorck_constraint_for_ty(span, for_ty, depth, ty)?;
|
||||
|
||||
for ty in dtorck_types {
|
||||
let ty = rcx.fcx.normalize_associated_types_in(span, &ty);
|
||||
let ty = rcx.fcx.resolve_type_vars_with_obligations(ty);
|
||||
let ty = rcx.fcx.resolve_type_and_region_vars_if_possible(&ty);
|
||||
match ty.sty {
|
||||
// All parameters live for the duration of the
|
||||
// function.
|
||||
ty::TyParam(..) => {}
|
||||
|
||||
// A projection that we couldn't resolve - it
|
||||
// might have a destructor.
|
||||
ty::TyProjection(..) | ty::TyAnon(..) => {
|
||||
rcx.type_must_outlive(origin(), ty, parent_scope);
|
||||
}
|
||||
|
||||
_ => {
|
||||
if let None = known.replace(ty) {
|
||||
types.push((ty, depth+1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for outlive in outlives {
|
||||
match outlive.unpack() {
|
||||
UnpackedKind::Lifetime(lt) => rcx.sub_regions(origin(), parent_scope, lt),
|
||||
UnpackedKind::Type(ty) => rcx.type_must_outlive(origin(), ty, parent_scope),
|
||||
}
|
||||
let cause = &ObligationCause::misc(span, body_id);
|
||||
let infer_ok = rcx.infcx.at(cause, rcx.fcx.param_env).dropck_outlives(ty);
|
||||
debug!("dropck_outlives = {:#?}", infer_ok);
|
||||
let kinds = rcx.fcx.register_infer_ok_obligations(infer_ok);
|
||||
for kind in kinds {
|
||||
match kind.unpack() {
|
||||
UnpackedKind::Lifetime(r) => rcx.sub_regions(origin(), parent_scope, r),
|
||||
UnpackedKind::Type(ty) => rcx.type_must_outlive(origin(), ty, parent_scope),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -411,8 +411,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||
self.type_of_node_must_outlive(origin, hir_id, var_region);
|
||||
|
||||
let typ = self.resolve_node_type(hir_id);
|
||||
let body_id = self.body_id;
|
||||
let _ = dropck::check_safety_of_destructor_if_necessary(
|
||||
self, typ, span, var_scope);
|
||||
self, typ, span, body_id, var_scope);
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -884,8 +885,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||
match *region {
|
||||
ty::ReScope(rvalue_scope) => {
|
||||
let typ = self.resolve_type(cmt.ty);
|
||||
let body_id = self.body_id;
|
||||
let _ = dropck::check_safety_of_destructor_if_necessary(
|
||||
self, typ, span, rvalue_scope);
|
||||
self, typ, span, body_id, rvalue_scope);
|
||||
}
|
||||
ty::ReStatic => {}
|
||||
_ => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user