--- /dev/null
+//! Miscellaneous type-system utilities that are too small to deserve their own modules.
+
+use crate::middle::lang_items;
+use crate::traits::{self, ObligationCause};
+use crate::ty::util::NeedsDrop;
+use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
+
+use rustc_hir as hir;
+use rustc_span::DUMMY_SP;
+
+#[derive(Clone)]
+pub enum CopyImplementationError<'tcx> {
+ InfrigingFields(Vec<&'tcx ty::FieldDef>),
+ NotAnAdt,
+ HasDestructor,
+}
+
+pub fn can_type_implement_copy(
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ self_type: Ty<'tcx>,
+) -> Result<(), CopyImplementationError<'tcx>> {
+ // FIXME: (@jroesch) float this code up
+ tcx.infer_ctxt().enter(|infcx| {
+ let (adt, substs) = match self_type.kind {
+ // These types used to have a builtin impl.
+ // Now libcore provides that impl.
+ ty::Uint(_)
+ | ty::Int(_)
+ | ty::Bool
+ | ty::Float(_)
+ | ty::Char
+ | ty::RawPtr(..)
+ | ty::Never
+ | ty::Ref(_, _, hir::Mutability::Not) => return Ok(()),
+
+ ty::Adt(adt, substs) => (adt, substs),
+
+ _ => return Err(CopyImplementationError::NotAnAdt),
+ };
+
+ let mut infringing = Vec::new();
+ for variant in &adt.variants {
+ for field in &variant.fields {
+ let ty = field.ty(tcx, substs);
+ if ty.references_error() {
+ continue;
+ }
+ let span = tcx.def_span(field.did);
+ let cause = ObligationCause { span, ..ObligationCause::dummy() };
+ let ctx = traits::FulfillmentContext::new();
+ match traits::fully_normalize(&infcx, ctx, cause, param_env, &ty) {
+ Ok(ty) => {
+ if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
+ infringing.push(field);
+ }
+ }
+ Err(errors) => {
+ infcx.report_fulfillment_errors(&errors, None, false);
+ }
+ };
+ }
+ }
+ if !infringing.is_empty() {
+ return Err(CopyImplementationError::InfrigingFields(infringing));
+ }
+ if adt.has_dtor(tcx) {
+ return Err(CopyImplementationError::HasDestructor);
+ }
+
+ Ok(())
+ })
+}
+
+fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+ is_item_raw(tcx, query, lang_items::CopyTraitLangItem)
+}
+
+fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+ is_item_raw(tcx, query, lang_items::SizedTraitLangItem)
+}
+
+fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+ is_item_raw(tcx, query, lang_items::FreezeTraitLangItem)
+}
+
+fn is_item_raw<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+ item: lang_items::LangItem,
+) -> bool {
+ let (param_env, ty) = query.into_parts();
+ let trait_def_id = tcx.require_lang_item(item, None);
+ tcx.infer_ctxt().enter(|infcx| {
+ traits::type_known_to_meet_bound_modulo_regions(
+ &infcx,
+ param_env,
+ ty,
+ trait_def_id,
+ DUMMY_SP,
+ )
+ })
+}
+
+fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> NeedsDrop {
+ let (param_env, ty) = query.into_parts();
+
+ let needs_drop = |ty: Ty<'tcx>| -> bool { tcx.needs_drop_raw(param_env.and(ty)).0 };
+
+ assert!(!ty.needs_infer());
+
+ NeedsDrop(match ty.kind {
+ // Fast-path for primitive types
+ ty::Infer(ty::FreshIntTy(_))
+ | ty::Infer(ty::FreshFloatTy(_))
+ | ty::Bool
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Never
+ | ty::FnDef(..)
+ | ty::FnPtr(_)
+ | ty::Char
+ | ty::GeneratorWitness(..)
+ | ty::RawPtr(_)
+ | ty::Ref(..)
+ | ty::Str => false,
+
+ // Foreign types can never have destructors
+ ty::Foreign(..) => false,
+
+ // `ManuallyDrop` doesn't have a destructor regardless of field types.
+ ty::Adt(def, _) if Some(def.did) == tcx.lang_items().manually_drop() => false,
+
+ // Issue #22536: We first query `is_copy_modulo_regions`. It sees a
+ // normalized version of the type, and therefore will definitely
+ // know whether the type implements Copy (and thus needs no
+ // cleanup/drop/zeroing) ...
+ _ if ty.is_copy_modulo_regions(tcx, param_env, DUMMY_SP) => false,
+
+ // ... (issue #22536 continued) but as an optimization, still use
+ // prior logic of asking for the structural "may drop".
+
+ // FIXME(#22815): Note that this is a conservative heuristic;
+ // it may report that the type "may drop" when actual type does
+ // not actually have a destructor associated with it. But since
+ // the type absolutely did not have the `Copy` bound attached
+ // (see above), it is sound to treat it as having a destructor.
+
+ // User destructors are the only way to have concrete drop types.
+ ty::Adt(def, _) if def.has_dtor(tcx) => true,
+
+ // Can refer to a type which may drop.
+ // FIXME(eddyb) check this against a ParamEnv.
+ ty::Dynamic(..)
+ | ty::Projection(..)
+ | ty::Param(_)
+ | ty::Bound(..)
+ | ty::Placeholder(..)
+ | ty::Opaque(..)
+ | ty::Infer(_)
+ | ty::Error => true,
+
+ ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
+
+ // Zero-length arrays never contain anything to drop.
+ ty::Array(_, len) if len.try_eval_usize(tcx, param_env) == Some(0) => false,
+
+ // Structural recursion.
+ ty::Array(ty, _) | ty::Slice(ty) => needs_drop(ty),
+
+ ty::Closure(def_id, ref substs) => {
+ substs.as_closure().upvar_tys(def_id, tcx).any(needs_drop)
+ }
+
+ // Pessimistically assume that all generators will require destructors
+ // as we don't know if a destructor is a noop or not until after the MIR
+ // state transformation pass
+ ty::Generator(..) => true,
+
+ ty::Tuple(..) => ty.tuple_fields().any(needs_drop),
+
+ // unions don't have destructors because of the child types,
+ // only if they manually implement `Drop` (handled above).
+ ty::Adt(def, _) if def.is_union() => false,
+
+ ty::Adt(def, substs) => def
+ .variants
+ .iter()
+ .any(|variant| variant.fields.iter().any(|field| needs_drop(field.ty(tcx, substs)))),
+ })
+}
+
+pub fn provide(providers: &mut ty::query::Providers<'_>) {
+ *providers = ty::query::Providers {
+ is_copy_raw,
+ is_sized_raw,
+ is_freeze_raw,
+ needs_drop_raw,
+ ..*providers
+ };
+}
mod chalk_fulfill;
pub mod codegen;
mod coherence;
+pub mod drop;
mod engine;
pub mod error_reporting;
mod fulfill;
}
pub fn provide(providers: &mut ty::query::Providers<'_>) {
+ drop::provide(providers);
*providers = ty::query::Providers {
is_object_safe: object_safety::is_object_safe_provider,
specialization_graph_of: specialize::specialization_graph_provider,
context::provide(providers);
erase_regions::provide(providers);
layout::provide(providers);
- util::provide(providers);
constness::provide(providers);
*providers = ty::query::Providers {
asyncness,
use crate::hir::map::DefPathData;
use crate::ich::NodeIdHashingMode;
-use crate::middle::lang_items;
use crate::mir::interpret::{sign_extend, truncate};
-use crate::traits::{self, ObligationCause};
use crate::ty::layout::{Integer, IntegerExt};
use crate::ty::query::TyCtxtAt;
use crate::ty::subst::{GenericArgKind, InternalSubsts, Subst, SubstsRef};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_macros::HashStable;
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
use std::{cmp, fmt};
use syntax::ast;
use syntax::attr::{self, SignedInt, UnsignedInt};
}
}
-#[derive(Clone)]
-pub enum CopyImplementationError<'tcx> {
- InfrigingFields(Vec<&'tcx ty::FieldDef>),
- NotAnAdt,
- HasDestructor,
-}
-
/// Describes whether a type is representable. For types that are not
/// representable, 'SelfRecursive' and 'ContainsRecursive' are used to
/// distinguish between types that are recursive with themselves and types that
SelfRecursive(Vec<Span>),
}
-impl<'tcx> ty::ParamEnv<'tcx> {
- pub fn can_type_implement_copy(
- self,
- tcx: TyCtxt<'tcx>,
- self_type: Ty<'tcx>,
- ) -> Result<(), CopyImplementationError<'tcx>> {
- // FIXME: (@jroesch) float this code up
- tcx.infer_ctxt().enter(|infcx| {
- let (adt, substs) = match self_type.kind {
- // These types used to have a builtin impl.
- // Now libcore provides that impl.
- ty::Uint(_)
- | ty::Int(_)
- | ty::Bool
- | ty::Float(_)
- | ty::Char
- | ty::RawPtr(..)
- | ty::Never
- | ty::Ref(_, _, hir::Mutability::Not) => return Ok(()),
-
- ty::Adt(adt, substs) => (adt, substs),
-
- _ => return Err(CopyImplementationError::NotAnAdt),
- };
-
- let mut infringing = Vec::new();
- for variant in &adt.variants {
- for field in &variant.fields {
- let ty = field.ty(tcx, substs);
- if ty.references_error() {
- continue;
- }
- let span = tcx.def_span(field.did);
- let cause = ObligationCause { span, ..ObligationCause::dummy() };
- let ctx = traits::FulfillmentContext::new();
- match traits::fully_normalize(&infcx, ctx, cause, self, &ty) {
- Ok(ty) => {
- if !infcx.type_is_copy_modulo_regions(self, ty, span) {
- infringing.push(field);
- }
- }
- Err(errors) => {
- infcx.report_fulfillment_errors(&errors, None, false);
- }
- };
- }
- }
- if !infringing.is_empty() {
- return Err(CopyImplementationError::InfrigingFields(infringing));
- }
- if adt.has_dtor(tcx) {
- return Err(CopyImplementationError::HasDestructor);
- }
-
- Ok(())
- })
- }
-}
-
impl<'tcx> TyCtxt<'tcx> {
/// Creates a hash of the type `Ty` which will be the same no matter what crate
/// context it's calculated within. This is used by the `type_id` intrinsic.
}
}
-fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
- is_item_raw(tcx, query, lang_items::CopyTraitLangItem)
-}
-
-fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
- is_item_raw(tcx, query, lang_items::SizedTraitLangItem)
-}
-
-fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
- is_item_raw(tcx, query, lang_items::FreezeTraitLangItem)
-}
-
-fn is_item_raw<'tcx>(
- tcx: TyCtxt<'tcx>,
- query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
- item: lang_items::LangItem,
-) -> bool {
- let (param_env, ty) = query.into_parts();
- let trait_def_id = tcx.require_lang_item(item, None);
- tcx.infer_ctxt().enter(|infcx| {
- traits::type_known_to_meet_bound_modulo_regions(
- &infcx,
- param_env,
- ty,
- trait_def_id,
- DUMMY_SP,
- )
- })
-}
-
#[derive(Clone, HashStable)]
pub struct NeedsDrop(pub bool);
-fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> NeedsDrop {
- let (param_env, ty) = query.into_parts();
-
- let needs_drop = |ty: Ty<'tcx>| -> bool { tcx.needs_drop_raw(param_env.and(ty)).0 };
-
- assert!(!ty.needs_infer());
-
- NeedsDrop(match ty.kind {
- // Fast-path for primitive types
- ty::Infer(ty::FreshIntTy(_))
- | ty::Infer(ty::FreshFloatTy(_))
- | ty::Bool
- | ty::Int(_)
- | ty::Uint(_)
- | ty::Float(_)
- | ty::Never
- | ty::FnDef(..)
- | ty::FnPtr(_)
- | ty::Char
- | ty::GeneratorWitness(..)
- | ty::RawPtr(_)
- | ty::Ref(..)
- | ty::Str => false,
-
- // Foreign types can never have destructors
- ty::Foreign(..) => false,
-
- // `ManuallyDrop` doesn't have a destructor regardless of field types.
- ty::Adt(def, _) if Some(def.did) == tcx.lang_items().manually_drop() => false,
-
- // Issue #22536: We first query `is_copy_modulo_regions`. It sees a
- // normalized version of the type, and therefore will definitely
- // know whether the type implements Copy (and thus needs no
- // cleanup/drop/zeroing) ...
- _ if ty.is_copy_modulo_regions(tcx, param_env, DUMMY_SP) => false,
-
- // ... (issue #22536 continued) but as an optimization, still use
- // prior logic of asking for the structural "may drop".
-
- // FIXME(#22815): Note that this is a conservative heuristic;
- // it may report that the type "may drop" when actual type does
- // not actually have a destructor associated with it. But since
- // the type absolutely did not have the `Copy` bound attached
- // (see above), it is sound to treat it as having a destructor.
-
- // User destructors are the only way to have concrete drop types.
- ty::Adt(def, _) if def.has_dtor(tcx) => true,
-
- // Can refer to a type which may drop.
- // FIXME(eddyb) check this against a ParamEnv.
- ty::Dynamic(..)
- | ty::Projection(..)
- | ty::Param(_)
- | ty::Bound(..)
- | ty::Placeholder(..)
- | ty::Opaque(..)
- | ty::Infer(_)
- | ty::Error => true,
-
- ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
-
- // Zero-length arrays never contain anything to drop.
- ty::Array(_, len) if len.try_eval_usize(tcx, param_env) == Some(0) => false,
-
- // Structural recursion.
- ty::Array(ty, _) | ty::Slice(ty) => needs_drop(ty),
-
- ty::Closure(def_id, ref substs) => {
- substs.as_closure().upvar_tys(def_id, tcx).any(needs_drop)
- }
-
- // Pessimistically assume that all generators will require destructors
- // as we don't know if a destructor is a noop or not until after the MIR
- // state transformation pass
- ty::Generator(..) => true,
-
- ty::Tuple(..) => ty.tuple_fields().any(needs_drop),
-
- // unions don't have destructors because of the child types,
- // only if they manually implement `Drop` (handled above).
- ty::Adt(def, _) if def.is_union() => false,
-
- ty::Adt(def, substs) => def
- .variants
- .iter()
- .any(|variant| variant.fields.iter().any(|field| needs_drop(field.ty(tcx, substs)))),
- })
-}
-
pub enum ExplicitSelf<'tcx> {
ByValue,
ByReference(ty::Region<'tcx>, hir::Mutability),
}
}
}
-
-pub fn provide(providers: &mut ty::query::Providers<'_>) {
- *providers = ty::query::Providers {
- is_copy_raw,
- is_sized_raw,
- is_freeze_raw,
- needs_drop_raw,
- ..*providers
- };
-}
use lint::{LateContext, LintArray, LintContext};
use rustc::lint;
use rustc::lint::FutureIncompatibleInfo;
+use rustc::traits::drop::can_type_implement_copy;
use rustc::ty::{self, layout::VariantIdx, Ty, TyCtxt};
use rustc_data_structures::fx::FxHashSet;
use rustc_feature::Stability;
if ty.is_copy_modulo_regions(cx.tcx, param_env, item.span) {
return;
}
- if param_env.can_type_implement_copy(cx.tcx, ty).is_ok() {
+ if can_type_implement_copy(cx.tcx, param_env, ty).is_ok() {
cx.span_lint(
MISSING_COPY_IMPLEMENTATIONS,
item.span,
use rustc::middle::privacy::AccessLevels;
use rustc::middle::stability::{DeprecationEntry, Index};
use rustc::session::Session;
+use rustc::traits::drop::can_type_implement_copy;
use rustc::ty::query::Providers;
use rustc::ty::TyCtxt;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
.emit();
} else {
let param_env = self.tcx.param_env(def_id);
- if !param_env.can_type_implement_copy(self.tcx, ty).is_ok() {
+ if !can_type_implement_copy(self.tcx, param_env, ty).is_ok() {
feature_err(
&self.tcx.sess.parse_sess,
sym::untagged_unions,
use rustc::middle::region;
use rustc::infer;
+use rustc::traits::drop::{can_type_implement_copy, CopyImplementationError};
use rustc::traits::predicate_for_trait_def;
use rustc::traits::{self, ObligationCause, TraitEngine};
use rustc::ty::adjustment::CoerceUnsizedInfo;
-use rustc::ty::util::CopyImplementationError;
use rustc::ty::TypeFoldable;
use rustc::ty::{self, Ty, TyCtxt};
debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
- match param_env.can_type_implement_copy(tcx, self_type) {
+ match can_type_implement_copy(tcx, param_env, self_type) {
Ok(()) => {}
Err(CopyImplementationError::InfrigingFields(fields)) => {
let item = tcx.hir().expect_item(impl_hir_id);