From 843db01bd925279da0a56efde532c9e3ecf73610 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 15 Apr 2015 11:57:29 +1200 Subject: [PATCH 1/7] eddyb's changes for DST coercions + lots of rebasing --- src/liballoc/boxed.rs | 8 + src/liballoc/rc.rs | 4 +- src/libcore/intrinsics.rs | 7 + src/libcore/marker.rs | 8 + src/libcore/mem.rs | 34 +++ src/libcore/nonzero.rs | 5 + src/libcore/ops.rs | 34 +++ src/librustc/diagnostics.rs | 3 + src/librustc/metadata/common.rs | 2 + src/librustc/metadata/csearch.rs | 8 + src/librustc/metadata/decoder.rs | 10 + src/librustc/metadata/encoder.rs | 10 + src/librustc/middle/expr_use_visitor.rs | 4 - src/librustc/middle/lang_items.rs | 3 + src/librustc/middle/traits/error_reporting.rs | 56 +++- src/librustc/middle/traits/mod.rs | 10 +- src/librustc/middle/traits/select.rs | 243 +++++++++++++++- src/librustc/middle/traits/util.rs | 21 +- src/librustc/middle/ty.rs | 52 +++- src/librustc_trans/trans/expr.rs | 210 +++++++++----- src/librustc_trans/trans/glue.rs | 4 +- src/librustc_trans/trans/intrinsic.rs | 26 ++ src/librustc_typeck/check/coercion.rs | 264 ++++++------------ src/librustc_typeck/check/method/mod.rs | 4 +- src/librustc_typeck/check/mod.rs | 86 +++++- src/librustc_typeck/check/regionck.rs | 4 +- src/librustc_typeck/check/vtable.rs | 186 ------------ src/librustc_typeck/check/wf.rs | 4 +- src/librustc_typeck/coherence/mod.rs | 172 +++++++++++- src/librustc_typeck/coherence/orphan.rs | 7 +- src/librustc_typeck/diagnostics.rs | 12 +- .../compile-fail/destructure-trait-ref.rs | 2 +- src/test/compile-fail/dst-bad-coercions.rs | 14 - src/test/compile-fail/issue-19692.rs | 2 +- src/test/compile-fail/issue-20261.rs | 1 - src/test/compile-fail/issue-22034.rs | 3 +- .../object-lifetime-default-elision.rs | 2 +- .../object-lifetime-default-from-box-error.rs | 4 +- ...ions-close-over-type-parameter-multiple.rs | 2 +- .../regions-trait-object-subtyping.rs | 2 +- 40 files changed, 1019 insertions(+), 514 deletions(-) delete mode 100644 src/librustc_typeck/check/vtable.rs diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index a0d60be3000..757c799d85c 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -62,6 +62,11 @@ use core::ops::{Deref, DerefMut}; use core::ptr::{Unique}; use core::raw::{TraitObject}; +#[cfg(not(stage0))] // SNAP c64d671 +use core::marker::Unsize; +#[cfg(not(stage0))] // SNAP c64d671 +use core::ops::CoerceUnsized; + /// A value that represents the heap. This is the default place that the `box` /// keyword allocates into when no place is supplied. /// @@ -390,3 +395,6 @@ impl<'a,A,R> FnOnce for Box+Send+'a> { self.call_box(args) } } + +#[cfg(not(stage0))] // SNAP c64d671 +impl, U: ?Sized> CoerceUnsized> for Box {} diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 015d0330ed7..a1b5e6e6baf 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -173,9 +173,9 @@ use core::intrinsics::assume; use heap::deallocate; struct RcBox { - value: T, strong: Cell, - weak: Cell + weak: Cell, + value: T } /// A reference-counted pointer type over an immutable value. diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 100b7e70591..d94b8884112 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -193,6 +193,13 @@ extern "rust-intrinsic" { pub fn min_align_of() -> usize; pub fn pref_align_of() -> usize; + #[cfg(not(stage0))] + pub fn size_of_val(_: &T) -> usize; + #[cfg(not(stage0))] + pub fn min_align_of_val(_: &T) -> usize; + #[cfg(not(stage0))] + pub fn drop_in_place(_: *mut T); + /// Gets a static string slice containing the name of a type. pub fn type_name() -> &'static str; diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 3aaedaeb813..968f68a78a7 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -53,6 +53,14 @@ pub trait Sized { // Empty. } +/// Types that can be "unsized" to a dynamically sized type. +#[unstable(feature = "core")] +#[cfg(not(stage0))] // SNAP c64d671 +#[lang="unsize"] +pub trait Unsize { + // Empty. +} + /// Types that can be copied by simply copying bits (i.e. `memcpy`). /// /// By default, variable bindings have 'move semantics.' In other diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index a149af3a440..bb94cd886d7 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -86,6 +86,22 @@ pub fn size_of() -> usize { unsafe { intrinsics::size_of::() } } +/// Returns the size of the type that `val` points to in bytes. +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// assert_eq!(4, mem::size_of_val(&5i32)); +/// ``` +#[cfg(not(stage0))] // SNAP c64d671 +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn size_of_val(val: &T) -> usize { + unsafe { intrinsics::size_of_val(val) } +} + /// Returns the size of the type that `_val` points to in bytes. /// /// # Examples @@ -95,6 +111,7 @@ pub fn size_of() -> usize { /// /// assert_eq!(4, mem::size_of_val(&5i32)); /// ``` +#[cfg(stage0)] // SNAP c64d671 #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn size_of_val(_val: &T) -> usize { @@ -118,6 +135,22 @@ pub fn min_align_of() -> usize { unsafe { intrinsics::min_align_of::() } } +/// Returns the ABI-required minimum alignment of the type of the value that `val` points to +/// +/// # Examples +/// +/// ``` +/// use std::mem; +/// +/// assert_eq!(4, mem::min_align_of_val(&5i32)); +/// ``` +#[cfg(not(stage0))] // SNAP c64d671 +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn min_align_of_val(val: &T) -> usize { + unsafe { intrinsics::min_align_of_val(val) } +} + /// Returns the ABI-required minimum alignment of the type of the value that `_val` points to /// /// # Examples @@ -127,6 +160,7 @@ pub fn min_align_of() -> usize { /// /// assert_eq!(4, mem::min_align_of_val(&5i32)); /// ``` +#[cfg(stage0)] // SNAP c64d671 #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn min_align_of_val(_val: &T) -> usize { diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 13b6468105d..85957382826 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -12,6 +12,8 @@ use marker::Sized; use ops::Deref; +#[cfg(not(stage0))] // SNAP c64d671 +use ops::CoerceUnsized; /// Unsafe trait to indicate what types are usable with the NonZero struct pub unsafe trait Zeroable {} @@ -54,3 +56,6 @@ impl Deref for NonZero { inner } } + +#[cfg(not(stage0))] // SNAP c64d671 +impl, U: Zeroable> CoerceUnsized> for NonZero {} diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 55c4264b10c..1a2473fda41 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -70,6 +70,9 @@ use marker::Sized; use fmt; +#[cfg(not(stage0))] // SNAP c64d671 +use marker::Unsize; + /// The `Drop` trait is used to run some code when a value goes out of scope. This /// is sometimes called a 'destructor'. /// @@ -1207,3 +1210,34 @@ mod impls { } } } + +/// Trait that indicates that this is a pointer or a wrapper for one, +/// where unsizing can be performed on the pointee. +#[unstable(feature = "core")] +#[cfg(not(stage0))] // SNAP c64d671 +#[lang="coerce_unsized"] +pub trait CoerceUnsized { + // Empty. +} + +#[cfg(not(stage0))] // SNAP c64d671 +impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {} +#[cfg(not(stage0))] // SNAP c64d671 +impl<'a, 'b: 'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {} +#[cfg(not(stage0))] // SNAP c64d671 +impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {} +#[cfg(not(stage0))] // SNAP c64d671 +impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {} + +#[cfg(not(stage0))] // SNAP c64d671 +impl<'a, 'b: 'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} +#[cfg(not(stage0))] // SNAP c64d671 +impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a T {} + +#[cfg(not(stage0))] // SNAP c64d671 +impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} +#[cfg(not(stage0))] // SNAP c64d671 +impl, U: ?Sized> CoerceUnsized<*const U> for *mut T {} + +#[cfg(not(stage0))] // SNAP c64d671 +impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 6690e6831af..c8788f76081 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -807,6 +807,9 @@ register_diagnostics! { E0017, E0019, E0022, + E0038, + E0079, // enum variant: expected signed integer constant + E0080, // enum variant: constant evaluation error E0109, E0110, E0134, diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index b6202084296..f410626714f 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -259,3 +259,5 @@ pub const tag_codemap_filemap: usize = 0xa2; pub const tag_item_super_predicates: usize = 0xa3; pub const tag_defaulted_trait: usize = 0xa4; + +pub const tag_impl_coerce_unsized_kind: usize = 0xa5; diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 6caefec4878..8a35c012004 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -279,6 +279,14 @@ pub fn get_impl_polarity<'tcx>(tcx: &ty::ctxt<'tcx>, decoder::get_impl_polarity(&*cdata, def.node) } +pub fn get_custom_coerce_unsized_kind<'tcx>(tcx: &ty::ctxt<'tcx>, + def: ast::DefId) + -> Option { + let cstore = &tcx.sess.cstore; + let cdata = cstore.get_crate_data(def.krate); + decoder::get_custom_coerce_unsized_kind(&*cdata, def.node) +} + // Given a def_id for an impl, return the trait it implements, // if there is one. pub fn get_impl_trait<'tcx>(tcx: &ty::ctxt<'tcx>, diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 382dc437bdc..2f2a5d31c9f 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -489,6 +489,16 @@ pub fn get_impl_polarity<'tcx>(cdata: Cmd, } } +pub fn get_custom_coerce_unsized_kind<'tcx>(cdata: Cmd, + id: ast::NodeId) + -> Option { + let item_doc = lookup_item(id, cdata.data()); + reader::maybe_get_doc(item_doc, tag_impl_coerce_unsized_kind).map(|kind_doc| { + let mut decoder = reader::Decoder::new(kind_doc); + Decodable::decode(&mut decoder).unwrap() + }) +} + pub fn get_impl_trait<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>) diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index afc71f83975..86f33257e09 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -1219,6 +1219,16 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_attributes(rbml_w, &item.attrs); encode_unsafety(rbml_w, unsafety); encode_polarity(rbml_w, polarity); + + match tcx.custom_coerce_unsized_kinds.borrow().get(&local_def(item.id)) { + Some(&kind) => { + rbml_w.start_tag(tag_impl_coerce_unsized_kind); + kind.encode(rbml_w); + rbml_w.end_tag(); + } + None => {} + } + match ty.node { ast::TyPath(None, ref path) if path.segments.len() == 1 => { let name = path.segments.last().unwrap().identifier.name; diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 0458bd70346..7366ad94534 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -890,10 +890,6 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { } }; - debug!("walk_autoref: expr.id={} cmt_base={}", - expr.id, - cmt_base.repr(self.tcx())); - match *autoref { ty::AutoPtr(r, m) => { self.delegate.borrow(expr.id, diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index c2865e33849..273cd6b4f85 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -261,11 +261,14 @@ lets_do_this! { SendTraitLangItem, "send", send_trait; SizedTraitLangItem, "sized", sized_trait; + UnsizeTraitLangItem, "unsize", unsize_trait; CopyTraitLangItem, "copy", copy_trait; SyncTraitLangItem, "sync", sync_trait; DropTraitLangItem, "drop", drop_trait; + CoerceUnsizedTraitLangItem, "coerce_unsized", coerce_unsized_trait; + AddTraitLangItem, "add", add_trait; SubTraitLangItem, "sub", sub_trait; MulTraitLangItem, "mul", mul_trait; diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs index 79d08cd825d..2b82987480d 100644 --- a/src/librustc/middle/traits/error_reporting.rs +++ b/src/librustc/middle/traits/error_reporting.rs @@ -15,8 +15,12 @@ use super::{ Obligation, ObligationCauseCode, OutputTypeParameterMismatch, + TraitNotObjectSafe, PredicateObligation, SelectionError, + ObjectSafetyViolation, + MethodViolationCode, + object_safety_violations, }; use fmt_macros::{Parser, Piece, Position}; @@ -252,6 +256,54 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, note_obligation_cause(infcx, obligation); } } + + TraitNotObjectSafe(did) => { + span_err!(infcx.tcx.sess, obligation.cause.span, E0038, + "cannot convert to a trait object because trait `{}` is not object-safe", + ty::item_path_str(infcx.tcx, did)); + + for violation in object_safety_violations(infcx.tcx, did) { + match violation { + ObjectSafetyViolation::SizedSelf => { + infcx.tcx.sess.span_note( + obligation.cause.span, + "the trait cannot require that `Self : Sized`"); + } + + ObjectSafetyViolation::SupertraitSelf => { + infcx.tcx.sess.span_note( + obligation.cause.span, + "the trait cannot use `Self` as a type parameter \ + in the supertrait listing"); + } + + ObjectSafetyViolation::Method(method, + MethodViolationCode::StaticMethod) => { + infcx.tcx.sess.span_note( + obligation.cause.span, + &format!("method `{}` has no receiver", + method.name.user_string(infcx.tcx))); + } + + ObjectSafetyViolation::Method(method, + MethodViolationCode::ReferencesSelf) => { + infcx.tcx.sess.span_note( + obligation.cause.span, + &format!("method `{}` references the `Self` type \ + in its arguments or return type", + method.name.user_string(infcx.tcx))); + } + + ObjectSafetyViolation::Method(method, + MethodViolationCode::Generic) => { + infcx.tcx.sess.span_note( + obligation.cause.span, + &format!("method `{}` has generic type parameters", + method.name.user_string(infcx.tcx))); + } + } + } + } } } @@ -403,10 +455,6 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, "only the last field of a struct or enum variant \ may have a dynamically sized type") } - ObligationCauseCode::ObjectSized => { - span_note!(tcx.sess, cause_span, - "only sized types can be made into objects"); - } ObligationCauseCode::SharedStatic => { span_note!(tcx.sess, cause_span, "shared static variables must have a type that implements `Sync`"); diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index b221c4bb685..fe61bb5e4ea 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -28,6 +28,7 @@ use util::ppaux::Repr; pub use self::error_reporting::report_fulfillment_errors; pub use self::error_reporting::report_overflow_error; +pub use self::error_reporting::report_selection_error; pub use self::error_reporting::suggest_new_overflow_limit; pub use self::coherence::orphan_check; pub use self::coherence::overlapping_impls; @@ -48,6 +49,7 @@ pub use self::select::{MethodMatchedData}; // intentionally don't export variant pub use self::util::elaborate_predicates; pub use self::util::get_vtable_index_of_object_method; pub use self::util::trait_ref_for_builtin_bound; +pub use self::util::predicate_for_trait_def; pub use self::util::supertraits; pub use self::util::Supertraits; pub use self::util::supertrait_def_ids; @@ -121,9 +123,6 @@ pub enum ObligationCauseCode<'tcx> { // Types of fields (other than the last) in a struct must be sized. FieldSized, - // Only Sized types can be made into objects - ObjectSized, - // static items must have `Sync` type SharedStatic, @@ -159,6 +158,7 @@ pub enum SelectionError<'tcx> { OutputTypeParameterMismatch(ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>, ty::type_err<'tcx>), + TraitNotObjectSafe(ast::DefId), } pub struct FulfillmentError<'tcx> { @@ -536,7 +536,9 @@ impl<'tcx, N> Vtable<'tcx, N> { } } - pub fn map_nested(&self, op: F) -> Vtable<'tcx, M> where F: FnMut(&N) -> M { + pub fn map_nested(&self, op: F) -> Vtable<'tcx, M> where + F: FnMut(&N) -> M, + { match *self { VtableImpl(ref i) => VtableImpl(i.map_nested(op)), VtableDefaultImpl(ref t) => VtableDefaultImpl(t.map_nested(op)), diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index e199bb17bf9..2541bba5d9a 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -25,6 +25,8 @@ use super::{PredicateObligation, TraitObligation, ObligationCause}; use super::report_overflow_error; use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation}; use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch}; +use super::{ObjectCastObligation, Obligation}; +use super::TraitNotObjectSafe; use super::Selection; use super::SelectionResult; use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure, @@ -35,7 +37,7 @@ use super::util; use middle::fast_reject; use middle::subst::{Subst, Substs, TypeSpace, VecPerParamSpace}; -use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty}; +use middle::ty::{self, AsPredicate, RegionEscape, ToPolyTraitRef, Ty}; use middle::infer; use middle::infer::{InferCtxt, TypeFreshener}; use middle::ty_fold::TypeFoldable; @@ -207,6 +209,8 @@ enum SelectionCandidate<'tcx> { BuiltinObjectCandidate, + BuiltinUnsizeCandidate, + ErrorCandidate, } @@ -904,6 +908,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { try!(self.assemble_builtin_bound_candidates(bound, stack, &mut candidates)); } + None if self.tcx().lang_items.unsize_trait() == + Some(obligation.predicate.def_id()) => { + self.assemble_candidates_for_unsizing(obligation, &mut candidates); + } + Some(ty::BoundSend) | Some(ty::BoundSync) | None => { @@ -1356,6 +1365,64 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }).unwrap(); } + /// Search for unsizing that might apply to `obligation`. + fn assemble_candidates_for_unsizing(&mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>) { + // TODO is it Ok to skip the binder here? + let source = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); + let target = self.infcx.shallow_resolve(obligation.predicate.0.input_types()[0]); + + debug!("assemble_candidates_for_unsizing(source={}, target={})", + source.repr(self.tcx()), target.repr(self.tcx())); + + let may_apply = match (&source.sty, &target.sty) { + // Trait+Kx+'a -> Trait+Ky+'b (upcasts). + (&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => { + // Upcasts permit two things: + // + // 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo` + // 2. Tightening the region bound, e.g. `Foo+'a` to `Foo+'b` if `'a : 'b` + // + // Note that neither of these changes requires any + // change at runtime. Eventually this will be + // generalized. + // + // We always upcast when we can because of reason + // #2 (region bounds). + data_a.principal.def_id() == data_a.principal.def_id() && + data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) + } + + // T -> Trait. + (_, &ty::ty_trait(_)) => true, + + // Ambiguous handling is below T -> Trait, because inference + // variables can still implement Unsize and nested + // obligations will have the final say (likely deferred). + (&ty::ty_infer(ty::TyVar(_)), _) | + (_, &ty::ty_infer(ty::TyVar(_))) => { + debug!("assemble_candidates_for_unsizing: ambiguous"); + candidates.ambiguous = true; + false + } + + // [T; n] -> [T]. + (&ty::ty_vec(_, Some(_)), &ty::ty_vec(_, None)) => true, + + // Struct -> Struct. + (&ty::ty_struct(def_id_a, _), &ty::ty_struct(def_id_b, _)) => { + def_id_a == def_id_b + } + + _ => false + }; + + if may_apply { + candidates.vec.push(BuiltinUnsizeCandidate); + } + } + /////////////////////////////////////////////////////////////////////////// // WINNOW // @@ -1427,6 +1494,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &ClosureCandidate(..) | &FnPointerCandidate(..) | &BuiltinObjectCandidate(..) | + &&BuiltinUnsizeCandidate(..) | &DefaultImplObjectCandidate(..) | &BuiltinCandidate(..) => { // We have a where-clause so don't go around looking @@ -1855,11 +1923,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth + 1, &skol_ty); let skol_obligation = - try!(util::predicate_for_trait_def(self.tcx(), - derived_cause.clone(), - trait_def_id, - obligation.recursion_depth + 1, - normalized_ty)); + util::predicate_for_trait_def(self.tcx(), + derived_cause.clone(), + trait_def_id, + obligation.recursion_depth + 1, + normalized_ty, + vec![]); obligations.push(skol_obligation); Ok(self.infcx().plug_leaks(skol_map, snapshot, &obligations)) }) @@ -1949,6 +2018,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.confirm_projection_candidate(obligation); Ok(VtableParam(Vec::new())) } + + BuiltinUnsizeCandidate => { + let data = try!(self.confirm_builtin_unsize_candidate(obligation)); + Ok(VtableBuiltin(data)) + } } } @@ -2322,6 +2396,159 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + fn confirm_builtin_unsize_candidate(&mut self, + obligation: &TraitObligation<'tcx>,) + -> Result>, + SelectionError<'tcx>> { + let tcx = self.tcx(); + + // TODO is this skip_binder Ok? + let source = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); + let target = self.infcx.shallow_resolve(obligation.predicate.0.input_types()[0]); + + debug!("confirm_builtin_unsize_candidate(source={}, target={})", + source.repr(tcx), target.repr(tcx)); + + let mut nested = vec![]; + match (&source.sty, &target.sty) { + // Trait+Kx+'a -> Trait+Ky+'b (upcasts). + (&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => { + // See assemble_candidates_for_unsizing for more info. + let bounds = ty::ExistentialBounds { + region_bound: data_b.bounds.region_bound, + builtin_bounds: data_b.bounds.builtin_bounds, + projection_bounds: data_a.bounds.projection_bounds.clone(), + }; + + let new_trait = ty::mk_trait(tcx, data_a.principal.clone(), bounds); + let origin = infer::Misc(obligation.cause.span); + if self.infcx.sub_types(false, origin, new_trait, target).is_err() { + return Err(Unimplemented); + } + + // Register one obligation for 'a: 'b. + let cause = ObligationCause::new(obligation.cause.span, + obligation.cause.body_id, + ObjectCastObligation(target)); + let outlives = ty::OutlivesPredicate(data_a.bounds.region_bound, + data_b.bounds.region_bound); + nested.push(Obligation::with_depth(cause, + obligation.recursion_depth + 1, + ty::Binder(outlives).as_predicate())); + } + + // T -> Trait. + (_, &ty::ty_trait(ref data)) => { + let object_did = data.principal_def_id(); + if !object_safety::is_object_safe(tcx, object_did) { + return Err(TraitNotObjectSafe(object_did)); + } + + let cause = ObligationCause::new(obligation.cause.span, + obligation.cause.body_id, + ObjectCastObligation(target)); + let mut push = |predicate| { + nested.push(Obligation::with_depth(cause.clone(), + obligation.recursion_depth + 1, + predicate)); + }; + + // Create the obligation for casting from T to Trait. + push(data.principal_trait_ref_with_self_ty(tcx, source).as_predicate()); + + // We can only make objects from sized types. + let mut builtin_bounds = data.bounds.builtin_bounds; + builtin_bounds.insert(ty::BoundSized); + + // Create additional obligations for all the various builtin + // bounds attached to the object cast. (In other words, if the + // object type is Foo+Send, this would create an obligation + // for the Send check.) + for bound in &builtin_bounds { + if let Ok(tr) = util::trait_ref_for_builtin_bound(tcx, bound, source) { + push(tr.as_predicate()); + } else { + return Err(Unimplemented); + } + } + + // Create obligations for the projection predicates. + for bound in data.projection_bounds_with_self_ty(tcx, source) { + push(bound.as_predicate()); + } + + // If the type is `Foo+'a`, ensures that the type + // being cast to `Foo+'a` outlives `'a`: + let outlives = ty::OutlivesPredicate(source, + data.bounds.region_bound); + push(ty::Binder(outlives).as_predicate()); + } + + // [T; n] -> [T]. + (&ty::ty_vec(a, Some(_)), &ty::ty_vec(b, None)) => { + let origin = infer::Misc(obligation.cause.span); + if self.infcx.sub_types(false, origin, a, b).is_err() { + return Err(Unimplemented); + } + } + + // Struct -> Struct. + (&ty::ty_struct(def_id, substs_a), &ty::ty_struct(_, substs_b)) => { + let fields = ty::lookup_struct_fields(tcx, def_id).iter().map(|f| { + ty::lookup_field_type_unsubstituted(tcx, def_id, f.id) + }).collect::>(); + + // The last field of the structure has to exist and be a + // type parameter (for now, to avoid tracking edge cases). + let i = if let Some(&ty::ty_param(p)) = fields.last().map(|ty| &ty.sty) { + assert!(p.space == TypeSpace); + p.idx as usize + } else { + return Err(Unimplemented); + }; + + // Replace the type parameter chosen for unsizing with + // ty_err and ensure it does not affect any other fields. + // This could be checked after type collection for any struct + // with a potentially unsized trailing field. + let mut new_substs = substs_a.clone(); + new_substs.types.get_mut_slice(TypeSpace)[i] = tcx.types.err; + for &ty in fields.init() { + if ty::type_is_error(ty.subst(tcx, &new_substs)) { + return Err(Unimplemented); + } + } + + // Extract T and U from Struct and Struct. + let inner_source = *substs_a.types.get(TypeSpace, i); + let inner_target = *substs_b.types.get(TypeSpace, i); + + // Check that all the source structure with the unsized + // type parameter is a subtype of the target. + new_substs.types.get_mut_slice(TypeSpace)[i] = inner_target; + let new_struct = ty::mk_struct(tcx, def_id, tcx.mk_substs(new_substs)); + let origin = infer::Misc(obligation.cause.span); + if self.infcx.sub_types(false, origin, new_struct, target).is_err() { + return Err(Unimplemented); + } + + // Construct the nested T: Unsize predicate. + nested.push(util::predicate_for_trait_def(tcx, + obligation.cause.clone(), + obligation.predicate.def_id(), + obligation.recursion_depth + 1, + inner_source, + vec![inner_target])); + } + + _ => unreachable!() + }; + + Ok(VtableBuiltinData { + nested: VecPerParamSpace::new(nested, vec![], vec![]) + }) + } + /////////////////////////////////////////////////////////////////////////// // Matching // @@ -2683,6 +2910,7 @@ impl<'tcx> Repr<'tcx> for SelectionCandidate<'tcx> { ErrorCandidate => format!("ErrorCandidate"), BuiltinCandidate(b) => format!("BuiltinCandidate({:?})", b), BuiltinObjectCandidate => format!("BuiltinObjectCandidate"), + BuiltinUnsizeCandidate => format!("BuiltinUnsizeCandidate"), ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)), ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)), DefaultImplCandidate(t) => format!("DefaultImplCandidate({:?})", t), @@ -2756,7 +2984,8 @@ impl<'tcx> EvaluationResult<'tcx> { match *self { EvaluatedToOk | EvaluatedToAmbig | - EvaluatedToErr(OutputTypeParameterMismatch(..)) => + EvaluatedToErr(OutputTypeParameterMismatch(..)) | + EvaluatedToErr(TraitNotObjectSafe(_)) => true, EvaluatedToErr(Unimplemented) => diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index a6b2359c2b8..ea4bc029ed6 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -356,13 +356,13 @@ pub fn predicate_for_trait_ref<'tcx>( cause: ObligationCause<'tcx>, trait_ref: ty::TraitRef<'tcx>, recursion_depth: usize) - -> Result, ErrorReported> + -> PredicateObligation<'tcx> { - Ok(Obligation { + Obligation { cause: cause, recursion_depth: recursion_depth, predicate: trait_ref.as_predicate(), - }) + } } pub fn predicate_for_trait_def<'tcx>( @@ -370,13 +370,14 @@ pub fn predicate_for_trait_def<'tcx>( cause: ObligationCause<'tcx>, trait_def_id: ast::DefId, recursion_depth: usize, - param_ty: Ty<'tcx>) - -> Result, ErrorReported> + param_ty: Ty<'tcx>, + ty_params: Vec>) + -> PredicateObligation<'tcx> { let trait_ref = ty::TraitRef { def_id: trait_def_id, - substs: tcx.mk_substs(Substs::empty().with_self_ty(param_ty)) - }; + substs: tcx.mk_substs(Substs::new_trait(ty_params, vec![], param_ty)) + }); predicate_for_trait_ref(cause, trait_ref, recursion_depth) } @@ -389,7 +390,7 @@ pub fn predicate_for_builtin_bound<'tcx>( -> Result, ErrorReported> { let trait_ref = try!(trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty)); - predicate_for_trait_ref(cause, trait_ref, recursion_depth) + Ok(predicate_for_trait_ref(cause, trait_ref, recursion_depth)) } /// Cast a trait reference into a reference to one of its super @@ -561,6 +562,10 @@ impl<'tcx> Repr<'tcx> for super::SelectionError<'tcx> { a.repr(tcx), b.repr(tcx), c.repr(tcx)), + + super::TraitNotObjectSafe(ref tr) => + format!("TraitNotObjectSafe({})", + tr.repr(tcx)) } } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index e445b6bb300..961f8a79324 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -404,6 +404,12 @@ pub enum AutoRef<'tcx> { AutoUnsafe(ast::Mutability), } +#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] +pub enum CustomCoerceUnsized { + /// Records the index of the field being coerced. + Struct(usize) +} + #[derive(Clone, Copy, RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Debug)] pub struct param_index { pub space: subst::ParamSpace, @@ -818,6 +824,9 @@ pub struct ctxt<'tcx> { /// Maps Expr NodeId's to their constant qualification. pub const_qualif_map: RefCell>, + + /// Caches CoerceUnsized kinds for impls on custom types. + pub custom_coerce_unsized_kinds: RefCell>, } impl<'tcx> ctxt<'tcx> { @@ -2809,6 +2818,7 @@ pub fn mk_ctxt<'tcx>(s: Session, type_impls_copy_cache: RefCell::new(HashMap::new()), type_impls_sized_cache: RefCell::new(HashMap::new()), const_qualif_map: RefCell::new(NodeMap()), + custom_coerce_unsized_kinds: RefCell::new(DefIdMap()), } } @@ -5351,6 +5361,26 @@ pub fn trait_impl_polarity<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) } } +pub fn custom_coerce_unsized_kind<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId) + -> CustomCoerceUnsized { + memoized(&cx.custom_coerce_unsized_kinds, did, |did: DefId| { + let (kind, src) = if did.krate != ast::LOCAL_CRATE { + (csearch::get_custom_coerce_unsized_kind(cx, did), "external") + } else { + (None, "local") + }; + + match kind { + Some(kind) => kind, + None => { + cx.sess.bug(&format!("custom_coerce_unsized_kind: \ + {} impl `{}` is missing its kind", + src, item_path_str(cx, did))); + } + } + }) +} + pub fn impl_or_trait_item<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) -> ImplOrTraitItem<'tcx> { lookup_locally_or_in_crate_store("impl_or_trait_items", @@ -6012,6 +6042,20 @@ pub fn lookup_repr_hints(tcx: &ctxt, did: DefId) -> Rc> { }) } +// Look up a field ID, whether or not it's local +pub fn lookup_field_type_unsubstituted<'tcx>(tcx: &ctxt<'tcx>, + struct_id: DefId, + id: DefId) + -> Ty<'tcx> { + if id.krate == ast::LOCAL_CRATE { + node_id_to_type(tcx, id.node) + } else { + let mut tcache = tcx.tcache.borrow_mut(); + tcache.entry(id).or_insert_with(|| csearch::get_field_type(tcx, struct_id, id)).ty + } +} + + // Look up a field ID, whether or not it's local // Takes a list of type substs in case the struct is generic pub fn lookup_field_type<'tcx>(tcx: &ctxt<'tcx>, @@ -6019,13 +6063,7 @@ pub fn lookup_field_type<'tcx>(tcx: &ctxt<'tcx>, id: DefId, substs: &Substs<'tcx>) -> Ty<'tcx> { - let ty = if id.krate == ast::LOCAL_CRATE { - node_id_to_type(tcx, id.node) - } else { - let mut tcache = tcx.tcache.borrow_mut(); - tcache.entry(id).or_insert_with(|| csearch::get_field_type(tcx, struct_id, id)).ty - }; - ty.subst(tcx, substs) + lookup_field_type_unsubstituted(tcx, struct_id, id).subst(tcx, substs) } // Look up the list of field names and IDs for a given struct. diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 7be1f3813d7..0343571562f 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -56,8 +56,10 @@ use back::abi; use llvm::{self, ValueRef}; use middle::check_const; use middle::def; +use middle::lang_items::CoerceUnsizedTraitLangItem; use middle::mem_categorization::Typer; -use middle::subst::{self, Substs}; +use middle::subst::{Subst, Substs, VecPerParamSpace}; +use middle::traits; use trans::{_match, adt, asm, base, callee, closure, consts, controlflow}; use trans::base::*; use trans::build::*; @@ -304,7 +306,7 @@ pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>, source: Ty<'tcx>, target: Ty<'tcx>, old_info: Option, - param_substs: &'tcx subst::Substs<'tcx>) + param_substs: &'tcx Substs<'tcx>) -> ValueRef { let (source, target) = ty::struct_lockstep_tails(ccx.tcx(), source, target); match (&source.sty, &target.sty) { @@ -390,81 +392,155 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // (You might think there is a more elegant way to do this than a // skip_reborrows bool, but then you remember that the borrow checker exists). if skip_reborrows == 0 && adj.autoref.is_some() { - datum = unpack_datum!(bcx, apply_autoref(bcx, expr, datum)); + if !type_is_sized(bcx.tcx(), datum.ty) { + // Arrange cleanup + let lval = unpack_datum!(bcx, + datum.to_lvalue_datum(bcx, "ref_fat_ptr", expr.id)); + datum = unpack_datum!(bcx, ref_fat_ptr(bcx, lval)); + } else { + datum = unpack_datum!(bcx, auto_ref(bcx, datum, expr)); + } } if let Some(target) = adj.unsize { - datum = unpack_datum!(bcx, unsize_pointer(bcx, datum, - bcx.monomorphize(&target))); + // We do not arrange cleanup ourselves; if we already are an + // L-value, then cleanup will have already been scheduled (and + // the `datum.to_rvalue_datum` call below will emit code to zero + // the drop flag when moving out of the L-value). If we are an + // R-value, then we do not need to schedule cleanup. + let source_datum = unpack_datum!(bcx, + datum.to_rvalue_datum(bcx, "__coerce_source")); + + let target = bcx.monomorphize(&target); + let llty = type_of::type_of(bcx.ccx(), target); + + // HACK(eddyb) get around issues with lifetime intrinsics. + let scratch = alloca_no_lifetime(bcx, llty, "__coerce_target"); + let target_datum = Datum::new(scratch, target, + Rvalue::new(ByRef)); + bcx = coerce_unsized(bcx, expr.span, source_datum, target_datum); + datum = Datum::new(scratch, target, + RvalueExpr(Rvalue::new(ByRef))); } } } debug!("after adjustments, datum={}", datum.to_string(bcx.ccx())); - return DatumBlock::new(bcx, datum); + DatumBlock::new(bcx, datum) +} - fn apply_autoref<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &ast::Expr, - datum: Datum<'tcx, Expr>) - -> DatumBlock<'blk, 'tcx, Expr> { - let mut bcx = bcx; +fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + span: codemap::Span, + source: Datum<'tcx, Rvalue>, + target: Datum<'tcx, Rvalue>) + -> Block<'blk, 'tcx> { + let mut bcx = bcx; + debug!("coerce_unsized({} -> {})", + source.to_string(bcx.ccx()), + target.to_string(bcx.ccx())); - if !type_is_sized(bcx.tcx(), datum.ty) { - // Arrange cleanup - let lval = unpack_datum!(bcx, - datum.to_lvalue_datum(bcx, "ref_fat_ptr", expr.id)); - ref_fat_ptr(bcx, lval) - } else { - auto_ref(bcx, datum, expr) + match (&source.ty.sty, &target.ty.sty) { + (&ty::ty_uniq(a), &ty::ty_uniq(b)) | + (&ty::ty_rptr(_, ty::mt { ty: a, .. }), &ty::ty_rptr(_, ty::mt { ty: b, .. })) | + (&ty::ty_rptr(_, ty::mt { ty: a, .. }), &ty::ty_ptr(ty::mt { ty: b, .. })) | + (&ty::ty_ptr(ty::mt { ty: a, .. }), &ty::ty_ptr(ty::mt { ty: b, .. })) => { + let (inner_source, inner_target) = (a, b); + + let (base, old_info) = if !type_is_sized(bcx.tcx(), inner_source) { + // Normally, the source is a thin pointer and we are + // adding extra info to make a fat pointer. The exception + // is when we are upcasting an existing object fat pointer + // to use a different vtable. In that case, we want to + // load out the original data pointer so we can repackage + // it. + (Load(bcx, get_dataptr(bcx, source.val)), + Some(Load(bcx, get_len(bcx, source.val)))) + } else { + let val = if source.kind.is_by_ref() { + load_ty(bcx, source.val, source.ty) + } else { + source.val + }; + (val, None) + }; + + let info = unsized_info(bcx.ccx(), inner_source, inner_target, + old_info, bcx.fcx.param_substs); + + // Compute the base pointer. This doesn't change the pointer value, + // but merely its type. + let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), inner_target).ptr_to(); + let base = PointerCast(bcx, base, ptr_ty); + + Store(bcx, base, get_dataptr(bcx, target.val)); + Store(bcx, info, get_len(bcx, target.val)); } + + // This can be extended to enums and tuples in the future. + // (&ty::ty_enum(def_id_a, substs_a), &ty::ty_enum(def_id_b, substs_b)) | + (&ty::ty_struct(def_id_a, substs_a), &ty::ty_struct(def_id_b, substs_b)) => { + assert_eq!(def_id_a, def_id_b); + + // The target is already by-ref because it's to be written to. + let source = unpack_datum!(bcx, source.to_ref_datum(bcx)); + assert!(target.kind.is_by_ref()); + + let trait_substs = Substs::erased(VecPerParamSpace::new(vec![target.ty], + vec![source.ty], + Vec::new())); + let trait_ref = ty::Binder(Rc::new(ty::TraitRef { + def_id: langcall(bcx, Some(span), "coercion", + CoerceUnsizedTraitLangItem), + substs: bcx.tcx().mk_substs(trait_substs) + })); + + let kind = match fulfill_obligation(bcx.ccx(), span, trait_ref) { + traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { + ty::custom_coerce_unsized_kind(bcx.tcx(), impl_def_id) + } + vtable => { + bcx.sess().span_bug(span, &format!("invalid CoerceUnsized vtable: {}", + vtable.repr(bcx.tcx()))); + } + }; + + let repr_source = adt::represent_type(bcx.ccx(), source.ty); + let repr_target = adt::represent_type(bcx.ccx(), target.ty); + let fields = ty::lookup_struct_fields(bcx.tcx(), def_id_a); + + let coerce_index = match kind { + ty::CustomCoerceUnsized::Struct(i) => i + }; + assert!(coerce_index < fields.len()); + + for (i, field) in fields.iter().enumerate() { + let ll_source = adt::trans_field_ptr(bcx, &repr_source, source.val, 0, i); + let ll_target = adt::trans_field_ptr(bcx, &repr_target, target.val, 0, i); + + let ty = ty::lookup_field_type_unsubstituted(bcx.tcx(), + def_id_a, + field.id); + let field_source = ty.subst(bcx.tcx(), substs_a); + let field_target = ty.subst(bcx.tcx(), substs_b); + + // If this is the field we need to coerce, recurse on it. + if i == coerce_index { + coerce_unsized(bcx, span, + Datum::new(ll_source, field_source, + Rvalue::new(ByRef)), + Datum::new(ll_target, field_target, + Rvalue::new(ByRef))); + } else { + // Otherwise, simply copy the data from the source. + assert_eq!(field_source, field_target); + memcpy_ty(bcx, ll_target, ll_source, field_source); + } + } + } + _ => bcx.sess().bug(&format!("coerce_unsized: invalid coercion {} -> {}", + source.ty.repr(bcx.tcx()), + target.ty.repr(bcx.tcx()))) } - - fn unsize_pointer<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - datum: Datum<'tcx, Expr>, - target: Ty<'tcx>) - -> DatumBlock<'blk, 'tcx, Expr> { - let mut bcx = bcx; - let unsized_ty = ty::deref(target, true) - .expect("expr::unsize got non-pointer target type").ty; - debug!("unsize_lvalue(unsized_ty={})", unsized_ty.repr(bcx.tcx())); - - // We do not arrange cleanup ourselves; if we already are an - // L-value, then cleanup will have already been scheduled (and - // the `datum.to_rvalue_datum` call below will emit code to zero - // the drop flag when moving out of the L-value). If we are an - // R-value, then we do not need to schedule cleanup. - let datum = unpack_datum!(bcx, datum.to_rvalue_datum(bcx, "__unsize_ref")); - - let pointee_ty = ty::deref(datum.ty, true) - .expect("expr::unsize got non-pointer datum type").ty; - let (base, old_info) = if !type_is_sized(bcx.tcx(), pointee_ty) { - // Normally, the source is a thin pointer and we are - // adding extra info to make a fat pointer. The exception - // is when we are upcasting an existing object fat pointer - // to use a different vtable. In that case, we want to - // load out the original data pointer so we can repackage - // it. - (Load(bcx, get_dataptr(bcx, datum.val)), - Some(Load(bcx, get_len(bcx, datum.val)))) - } else { - (datum.val, None) - }; - - let info = unsized_info(bcx.ccx(), pointee_ty, unsized_ty, - old_info, bcx.fcx.param_substs); - - // Compute the base pointer. This doesn't change the pointer value, - // but merely its type. - let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), unsized_ty).ptr_to(); - let base = PointerCast(bcx, base, ptr_ty); - - let llty = type_of::type_of(bcx.ccx(), target); - // HACK(eddyb) get around issues with lifetime intrinsics. - let scratch = alloca_no_lifetime(bcx, llty, "__fat_ptr"); - Store(bcx, base, get_dataptr(bcx, scratch)); - Store(bcx, info, get_len(bcx, scratch)); - - DatumBlock::new(bcx, Datum::new(scratch, target, RvalueExpr(Rvalue::new(ByRef)))) - } + bcx } /// Translates an expression in "lvalue" mode -- meaning that it returns a reference to the memory @@ -1178,7 +1254,7 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pub fn trans_def_fn_unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ref_expr: &ast::Expr, def: def::Def, - param_substs: &'tcx subst::Substs<'tcx>) + param_substs: &'tcx Substs<'tcx>) -> Datum<'tcx, Rvalue> { let _icx = push_ctxt("trans_def_datum_unadjusted"); diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index a2a9e89ff63..fd1f22e1d9d 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -392,8 +392,8 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, contents_scope) } -fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info: ValueRef) - -> (ValueRef, ValueRef) { +pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info: ValueRef) + -> (ValueRef, ValueRef) { debug!("calculate size of DST: {}; with lost info: {}", bcx.ty_to_string(t), bcx.val_to_string(info)); if type_is_sized(bcx.tcx(), t) { diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 4b1bdd63dd7..951d30c4fb8 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -326,10 +326,31 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let lltp_ty = type_of::type_of(ccx, tp_ty); C_uint(ccx, machine::llsize_of_alloc(ccx, lltp_ty)) } + (_, "size_of_val") => { + let tp_ty = *substs.types.get(FnSpace, 0); + if !type_is_sized(tcx, tp_ty) { + let info = Load(bcx, expr::get_len(bcx, llargs[0])); + let (llsize, _) = glue::size_and_align_of_dst(bcx, tp_ty, info); + llsize + } else { + let lltp_ty = type_of::type_of(ccx, tp_ty); + C_uint(ccx, machine::llsize_of_alloc(ccx, lltp_ty)) + } + } (_, "min_align_of") => { let tp_ty = *substs.types.get(FnSpace, 0); C_uint(ccx, type_of::align_of(ccx, tp_ty)) } + (_, "min_align_of_val") => { + let tp_ty = *substs.types.get(FnSpace, 0); + if !type_is_sized(tcx, tp_ty) { + let info = Load(bcx, expr::get_len(bcx, llargs[0])); + let (_, llalign) = glue::size_and_align_of_dst(bcx, tp_ty, info); + llalign + } else { + C_uint(ccx, type_of::align_of(ccx, tp_ty)) + } + } (_, "pref_align_of") => { let tp_ty = *substs.types.get(FnSpace, 0); let lltp_ty = type_of::type_of(ccx, tp_ty); @@ -351,6 +372,11 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, bcx = src.store_to(bcx, llargs[0]); C_nil(ccx) } + (_, "drop_in_place") => { + let tp_ty = *substs.types.get(FnSpace, 0); + glue::drop_ty(bcx, llargs[0], tp_ty, call_debug_location); + C_nil(ccx) + } (_, "type_name") => { let tp_ty = *substs.types.get(FnSpace, 0); let ty_name = token::intern_and_get_ident(&ty_to_string(ccx.tcx(), tp_ty)); diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 28df1c21595..d33553f3859 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -61,25 +61,24 @@ //! we may want to adjust precisely when coercions occur. use check::{autoderef, FnCtxt, NoPreference, PreferMutLvalue, UnresolvedTypeAction}; -use check::vtable; use middle::infer::{self, Coercion}; -use middle::subst; -use middle::traits; +use middle::traits::{self, ObligationCause}; +use middle::traits::{predicate_for_trait_def, report_selection_error}; use middle::ty::{AutoDerefRef, AdjustDerefRef}; use middle::ty::{self, mt, Ty}; use middle::ty_relate::RelateResult; use util::common::indent; -use util::ppaux; use util::ppaux::Repr; -use std::cell::Cell; +use std::cell::RefCell; +use std::collections::VecDeque; use syntax::ast; struct Coerce<'a, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'tcx>, origin: infer::TypeOrigin, - unsizing_obligation: Cell>> + unsizing_obligations: RefCell>>, } type CoerceResult<'tcx> = RelateResult<'tcx, Option>>; @@ -94,15 +93,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Ok(None) // No coercion required. } - fn outlives(&self, - origin: infer::SubregionOrigin<'tcx>, - a: ty::Region, - b: ty::Region) - -> RelateResult<'tcx, ()> { - infer::mk_subr(self.fcx.infcx(), origin, b, a); - Ok(()) - } - fn unpack_actual_value(&self, a: Ty<'tcx>, f: F) -> T where F: FnOnce(Ty<'tcx>) -> T, { @@ -248,51 +238,94 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // or &mut [T, ..n] -> &mut [T] // or &Concrete -> &Trait, etc. fn coerce_unsized(&self, - a: Ty<'tcx>, - b: Ty<'tcx>) + source: Ty<'tcx>, + target: Ty<'tcx>) -> CoerceResult<'tcx> { - debug!("coerce_unsized(a={}, b={})", - a.repr(self.tcx()), - b.repr(self.tcx())); + debug!("coerce_unsized(source={}, target={})", + source.repr(self.tcx()), + target.repr(self.tcx())); + + let traits = (self.tcx().lang_items.unsize_trait(), + self.tcx().lang_items.coerce_unsized_trait()); + let (unsize_did, coerce_unsized_did) = if let (Some(u), Some(cu)) = traits { + (u, cu) + } else { + debug!("Missing Unsize or CoerceUnsized traits"); + return Err(ty::terr_mismatch); + }; // Note, we want to avoid unnecessary unsizing. We don't want to coerce to // a DST unless we have to. This currently comes out in the wash since // we can't unify [T] with U. But to properly support DST, we need to allow - // that, at which point we will need extra checks on b here. + // that, at which point we will need extra checks on the target here. - let (reborrow, target) = match (&a.sty, &b.sty) { + // Handle reborrows before selecting `Source: CoerceUnsized`. + let (source, reborrow) = match (&source.sty, &target.sty) { (&ty::ty_rptr(_, mt_a), &ty::ty_rptr(_, mt_b)) => { - if let Some(target) = self.unsize_ty(mt_a.ty, mt_b.ty) { - try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl)); + try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl)); - let coercion = Coercion(self.origin.span()); - let r_borrow = self.fcx.infcx().next_region_var(coercion); - let region = self.tcx().mk_region(r_borrow); - (Some(ty::AutoPtr(region, mt_b.mutbl)), target) - } else { - return Err(ty::terr_mismatch); - } + let coercion = Coercion(self.origin.span()); + let r_borrow = self.fcx.infcx().next_region_var(coercion); + let region = self.tcx().mk_region(r_borrow); + (mt_a.ty, Some(ty::AutoPtr(region, mt_b.mutbl))) } (&ty::ty_rptr(_, mt_a), &ty::ty_ptr(mt_b)) => { - if let Some(target) = self.unsize_ty(mt_a.ty, mt_b.ty) { - try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl)); - (Some(ty::AutoUnsafe(mt_b.mutbl)), target) - } else { - return Err(ty::terr_mismatch); - } + try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl)); + (mt_a.ty, Some(ty::AutoUnsafe(mt_b.mutbl))) } - (&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => { - if let Some(target) = self.unsize_ty(t_a, t_b) { - (None, ty::mk_uniq(self.tcx(), target)) - } else { - return Err(ty::terr_mismatch); - } - } - _ => return Err(ty::terr_mismatch) + _ => (source, None) }; + let source = ty::adjust_ty_for_autoref(self.tcx(), source, reborrow); + + let mut selcx = traits::SelectionContext::new(self.fcx.infcx(), self.fcx); + + // Use a FIFO queue for this custom fulfillment procedure. + let mut queue = VecDeque::new(); + let mut leftover_predicates = vec![]; + + // Create an obligation for `Source: CoerceUnsized`. + let cause = ObligationCause::misc(self.origin.span(), self.fcx.body_id); + queue.push_back(predicate_for_trait_def(self.tcx(), cause, coerce_unsized_did, + 0, source, vec![target])); + + // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid + // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where + // inference might unify those two inner type variables later. + let traits = [coerce_unsized_did, unsize_did]; + while let Some(obligation) = queue.pop_front() { + let trait_ref = match obligation.predicate { + ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => { + tr.clone() + } + _ => { + leftover_predicates.push(obligation); + continue; + } + }; + match selcx.select(&obligation.with(trait_ref)) { + // Uncertain or unimplemented. + Ok(None) | Err(traits::Unimplemented) => { + return Err(ty::terr_mismatch); + } + + // Object safety violations or miscellaneous. + Err(err) => { + report_selection_error(self.fcx.infcx(), &obligation, &err); + // Treat this like an obligation and follow through + // with the unsizing - the lack of a coercion should + // be silent, as it causes a type mismatch later. + } + + Ok(Some(vtable)) => { + vtable.map_move_nested(|o| queue.push_back(o)); + } + } + } + + let mut obligations = self.unsizing_obligations.borrow_mut(); + assert!(obligations.is_empty()); + *obligations = leftover_predicates; - let target = ty::adjust_ty_for_autoref(self.tcx(), target, reborrow); - try!(self.subtype(target, b)); let adjustment = AutoDerefRef { autoderefs: if reborrow.is_some() { 1 } else { 0 }, autoref: reborrow, @@ -302,108 +335,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Ok(Some(AdjustDerefRef(adjustment))) } - // Takes a type and returns an unsized version. - // E.g., `[T, ..n]` -> `[T]`. - fn unsize_ty(&self, - ty_a: Ty<'tcx>, - ty_b: Ty<'tcx>) - -> Option> { - let tcx = self.tcx(); - - self.unpack_actual_value(ty_a, |a| self.unpack_actual_value(ty_b, |b| { - debug!("unsize_ty(a={}, b={})", a.repr(self.tcx()), b.repr(self.tcx())); - match (&a.sty, &b.sty) { - (&ty::ty_vec(t_a, Some(_)), &ty::ty_vec(_, None)) => { - Some(ty::mk_vec(tcx, t_a, None)) - } - (&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => { - // Upcasts permit two things: - // - // 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo` - // 2. Tightening the region bound, e.g. `Foo+'a` to `Foo+'b` if `'a : 'b` - // - // Note that neither of these changes requires any - // change at runtime. Eventually this will be - // generalized. - // - // We always upcast when we can because of reason - // #2 (region bounds). - if data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) { - // construct a type `a1` which is a version of - // `a` using the upcast bounds from `b` - let bounds_a1 = ty::ExistentialBounds { - // From type b - region_bound: data_b.bounds.region_bound, - builtin_bounds: data_b.bounds.builtin_bounds, - - // From type a - projection_bounds: data_a.bounds.projection_bounds.clone(), - }; - let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1); - - // relate `a1` to `b` - let result = self.fcx.infcx().commit_if_ok(|_| { - // it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b - try!(self.outlives(infer::RelateObjectBound(self.origin.span()), - data_a.bounds.region_bound, - data_b.bounds.region_bound)); - self.subtype(ty_a1, ty_b) - }); - - // if that was successful, we have a coercion - match result { - Ok(_) => Some(ty_b), - Err(_) => None, - } - } else { - None - } - } - (_, &ty::ty_trait(_)) => { - assert!(self.unsizing_obligation.get().is_none()); - self.unsizing_obligation.set(Some(a)); - Some(ty_b) - } - (&ty::ty_struct(did_a, substs_a), &ty::ty_struct(did_b, substs_b)) - if did_a == did_b => { - debug!("unsizing a struct"); - // Try unsizing each type param in turn to see if we end up with ty_b. - let ty_substs_a = substs_a.types.get_slice(subst::TypeSpace); - let ty_substs_b = substs_b.types.get_slice(subst::TypeSpace); - assert!(ty_substs_a.len() == ty_substs_b.len()); - - let tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate(); - for (i, (tp_a, tp_b)) in tps { - if self.subtype(*tp_a, *tp_b).is_ok() { - continue; - } - if let Some(new_tp) = self.unsize_ty(tp_a, tp_b) { - // Check that the whole types match. - let mut new_substs = substs_a.clone(); - new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp; - let ty = ty::mk_struct(tcx, did_a, tcx.mk_substs(new_substs)); - if self.subtype(ty, ty_b).is_err() { - debug!("Unsized type parameter '{}', but still \ - could not match types {} and {}", - ppaux::ty_to_string(tcx, tp_a), - ppaux::ty_to_string(tcx, ty), - ppaux::ty_to_string(tcx, ty_b)); - // We can only unsize a single type parameter, so - // if we unsize one and it doesn't give us the - // type we want, then we won't succeed later. - break; - } - - return Some(ty); - } - } - None - } - _ => None - } - })) - } - fn coerce_from_fn_pointer(&self, a: Ty<'tcx>, fn_ty_a: &'tcx ty::BareFnTy<'tcx>, @@ -496,41 +427,24 @@ pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { debug!("mk_assignty({} -> {})", a.repr(fcx.tcx()), b.repr(fcx.tcx())); - let (adjustment, unsizing_obligation) = try!(indent(|| { + let mut unsizing_obligations = vec![]; + let adjustment = try!(indent(|| { fcx.infcx().commit_if_ok(|_| { let coerce = Coerce { fcx: fcx, origin: infer::ExprAssignable(expr.span), - unsizing_obligation: Cell::new(None) + unsizing_obligations: RefCell::new(vec![]) }; - Ok((try!(coerce.coerce(expr, a, b)), - coerce.unsizing_obligation.get())) + let adjustment = try!(coerce.coerce(expr, a, b)); + unsizing_obligations = coerce.unsizing_obligations.into_inner(); + Ok(adjustment) }) })); if let Some(AdjustDerefRef(auto)) = adjustment { - if let (Some(source), Some(target)) = (unsizing_obligation, auto.unsize) { - let target = ty::deref(target, true) - .expect("coercion: unsizing got non-pointer target type").ty; - let target = ty::struct_tail(fcx.tcx(), target); - if let ty::ty_trait(ref ty_trait) = target.sty { - vtable::check_object_safety(fcx.tcx(), ty_trait, expr.span); - - // If the type is `Foo+'a`, ensures that the type - // being cast to `Foo+'a` implements `Foo`: - vtable::register_object_cast_obligations(fcx, - expr.span, - ty_trait, - source); - - // If the type is `Foo+'a`, ensures that the type - // being cast to `Foo+'a` outlives `'a`: - let cause = traits::ObligationCause { - span: expr.span, - body_id: fcx.body_id, - code: traits::ObjectCastObligation(source) - }; - fcx.register_region_obligation(source, ty_trait.bounds.region_bound, cause); + if auto.unsize.is_some() { + for obligation in unsizing_obligations { + fcx.register_predicate(obligation); } } } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index c070df6b593..fb2ad444005 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -12,8 +12,6 @@ use astconv::AstConv; use check::FnCtxt; -use check::vtable; -use check::vtable::select_new_fcx_obligations; use middle::def; use middle::privacy::{AllPublic, DependsOn, LastPrivate, LastMod}; use middle::subst; @@ -233,7 +231,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // FIXME(#18653) -- Try to resolve obligations, giving us more // typing information, which can sometimes be needed to avoid // pathological region inference failures. - vtable::select_new_fcx_obligations(fcx); + fcx.select_new_obligations(); // Insert any adjustments needed (always an autoref of some mutability). match self_expr { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 3769e9fa0f3..554f3d4b5a0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -93,7 +93,7 @@ use middle::pat_util::{self, pat_id_map}; use middle::privacy::{AllPublic, LastMod}; use middle::region::{self, CodeExtent}; use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace}; -use middle::traits; +use middle::traits::{self, report_fulfillment_errors}; use middle::ty::{FnSig, GenericPredicates, TypeScheme}; use middle::ty::{Disr, ParamTy, ParameterEnvironment}; use middle::ty::{self, HasProjectionTypes, RegionEscape, ToPolyTraitRef, Ty}; @@ -129,7 +129,6 @@ use syntax::visit::{self, Visitor}; mod assoc; pub mod dropck; pub mod _match; -pub mod vtable; pub mod writeback; pub mod regionck; pub mod coercion; @@ -525,9 +524,9 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let fcx = check_fn(ccx, fn_ty.unsafety, fn_id, &fn_sig, decl, fn_id, body, &inh); - vtable::select_all_fcx_obligations_and_apply_defaults(&fcx); + fcx.select_all_obligations_and_apply_defaults(); upvar::closure_analyze_fn(&fcx, fn_id, decl, body); - vtable::select_all_fcx_obligations_or_error(&fcx); + fcx.select_all_obligations_or_error(); fcx.check_casts(); regionck::regionck_fn(&fcx, fn_id, fn_span, decl, body); writeback::resolve_type_vars_in_fn(&fcx, decl, body); @@ -1290,7 +1289,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // If not, try resolving any new fcx obligations that have cropped up. - vtable::select_new_fcx_obligations(self); + self.select_new_obligations(); ty = self.infcx().resolve_type_vars_if_possible(&ty); if !ty::type_has_ty_infer(ty) { debug!("resolve_type_vars_if_possible: ty={}", ty.repr(self.tcx())); @@ -1301,7 +1300,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // possible. This can help substantially when there are // indirect dependencies that don't seem worth tracking // precisely. - vtable::select_fcx_obligations_where_possible(self); + self.select_obligations_where_possible(); ty = self.infcx().resolve_type_vars_if_possible(&ty); debug!("resolve_type_vars_if_possible: ty={}", ty.repr(self.tcx())); @@ -1817,6 +1816,57 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { deferred_cast_checks.clear(); } + + fn select_all_obligations_and_apply_defaults(&self) { + debug!("select_all_obligations_and_apply_defaults"); + + self.select_obligations_where_possible(); + self.default_type_parameters(); + self.select_obligations_where_possible(); + } + + fn select_all_obligations_or_error(&self) { + debug!("select_all_obligations_or_error"); + + // upvar inference should have ensured that all deferred call + // resolutions are handled by now. + assert!(self.inh.deferred_call_resolutions.borrow().is_empty()); + + self.select_all_obligations_and_apply_defaults(); + let mut fulfillment_cx = self.inh.fulfillment_cx.borrow_mut(); + match fulfillment_cx.select_all_or_error(self.infcx(), self) { + Ok(()) => { } + Err(errors) => { report_fulfillment_errors(self.infcx(), &errors); } + } + } + + /// Select as many obligations as we can at present. + fn select_obligations_where_possible(&self) { + match + self.inh.fulfillment_cx + .borrow_mut() + .select_where_possible(self.infcx(), self) + { + Ok(()) => { } + Err(errors) => { report_fulfillment_errors(self.infcx(), &errors); } + } + } + + /// Try to select any fcx obligation that we haven't tried yet, in an effort + /// to improve inference. You could just call + /// `select_obligations_where_possible` except that it leads to repeated + /// work. + fn select_new_obligations(&self) { + match + self.inh.fulfillment_cx + .borrow_mut() + .select_new_obligations(self.infcx(), self) + { + Ok(()) => { } + Err(errors) => { report_fulfillment_errors(self.infcx(), &errors); } + } + } + } impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> { @@ -1880,11 +1930,7 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, for autoderefs in 0..fcx.tcx().sess.recursion_limit.get() { let resolved_t = match unresolved_type_action { UnresolvedTypeAction::Error => { - let resolved_t = structurally_resolved_type(fcx, sp, t); - if ty::type_is_error(resolved_t) { - return (resolved_t, autoderefs, None); - } - resolved_t + structurally_resolved_type(fcx, sp, t) } UnresolvedTypeAction::Ignore => { // We can continue even when the type cannot be resolved @@ -1894,6 +1940,9 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, fcx.resolve_type_vars_if_possible(t) } }; + if ty::type_is_error(resolved_t) { + return (resolved_t, autoderefs, None); + } match should_stop(resolved_t, autoderefs) { Some(x) => return (resolved_t, autoderefs, Some(x)), @@ -2263,7 +2312,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // an "opportunistic" vtable resolution of any trait bounds on // the call. This helps coercions. if check_blocks { - vtable::select_new_fcx_obligations(fcx); + fcx.select_new_obligations(); } // For variadic functions, we don't have a declared type for all of @@ -4059,7 +4108,7 @@ fn check_const_with_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, check_expr_with_hint(fcx, e, declty); demand::coerce(fcx, e.span, declty, e); - vtable::select_all_fcx_obligations_or_error(fcx); + fcx.select_all_obligations_or_error(); fcx.check_casts(); regionck::regionck_expr(fcx, e); writeback::resolve_type_vars_in_expr(fcx, e); @@ -4928,6 +4977,14 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { "breakpoint" => (0, Vec::new(), ty::mk_nil(tcx)), "size_of" | "pref_align_of" | "min_align_of" => (1, Vec::new(), ccx.tcx.types.usize), + "size_of_val" | "min_align_of_val" => { + (1, vec![ + ty::mk_imm_rptr(tcx, + tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), + ty::BrAnon(0))), + param(ccx, 0)) + ], ccx.tcx.types.usize) + } "init" | "init_dropped" => (1, Vec::new(), param(ccx, 0)), "uninit" => (1, Vec::new(), param(ccx, 0)), "forget" => (1, vec!( param(ccx, 0) ), ty::mk_nil(tcx)), @@ -4943,6 +5000,9 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { ), ty::mk_nil(tcx)) } + "drop_in_place" => { + (1, vec![ty::mk_mut_ptr(tcx, param(ccx, 0))], ty::mk_nil(tcx)) + } "needs_drop" => (1, Vec::new(), ccx.tcx.types.bool), "type_name" => (1, Vec::new(), ty::mk_str_slice(tcx, tcx.mk_region(ty::ReStatic), diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 19cb570c82d..337088c313d 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -85,8 +85,6 @@ use astconv::AstConv; use check::dropck; use check::FnCtxt; -use check::vtable; -use middle::free_region::FreeRegionMap; use middle::implicator; use middle::mem_categorization as mc; use middle::region::CodeExtent; @@ -312,7 +310,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { // region checking can introduce new pending obligations // which, when processed, might generate new region // obligations. So make sure we process those. - vtable::select_all_fcx_obligations_or_error(self.fcx); + self.fcx.select_all_obligations_or_error(); // Make a copy of the region obligations vec because we'll need // to be able to borrow the fulfillment-cx below when projecting. diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs deleted file mode 100644 index a9094fce57c..00000000000 --- a/src/librustc_typeck/check/vtable.rs +++ /dev/null @@ -1,186 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use check::FnCtxt; -use middle::traits::{self, ObjectSafetyViolation, MethodViolationCode}; -use middle::traits::{Obligation, ObligationCause}; -use middle::traits::report_fulfillment_errors; -use middle::ty::{self, Ty, AsPredicate}; -use syntax::codemap::Span; -use util::ppaux::{Repr, UserString}; - - -// Check that a trait is 'object-safe'. This should be checked whenever a trait object -// is created (by casting or coercion, etc.). A trait is object-safe if all its -// methods are object-safe. A trait method is object-safe if it does not take -// self by value, has no type parameters and does not use the `Self` type, except -// in self position. -pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>, - object_trait: &ty::TyTrait<'tcx>, - span: Span) -{ - let trait_def_id = object_trait.principal_def_id(); - - if traits::is_object_safe(tcx, trait_def_id) { - return; - } - - span_err!(tcx.sess, span, E0038, - "cannot convert to a trait object because trait `{}` is not object-safe", - ty::item_path_str(tcx, trait_def_id)); - - let violations = traits::object_safety_violations(tcx, trait_def_id); - for violation in violations { - match violation { - ObjectSafetyViolation::SizedSelf => { - tcx.sess.span_note( - span, - "the trait cannot require that `Self : Sized`"); - } - - ObjectSafetyViolation::SupertraitSelf => { - tcx.sess.span_note( - span, - "the trait cannot use `Self` as a type parameter \ - in the supertrait listing"); - } - - ObjectSafetyViolation::Method(method, MethodViolationCode::StaticMethod) => { - tcx.sess.span_note( - span, - &format!("method `{}` has no receiver", - method.name.user_string(tcx))); - } - - ObjectSafetyViolation::Method(method, MethodViolationCode::ReferencesSelf) => { - tcx.sess.span_note( - span, - &format!("method `{}` references the `Self` type \ - in its arguments or return type", - method.name.user_string(tcx))); - } - - ObjectSafetyViolation::Method(method, MethodViolationCode::Generic) => { - tcx.sess.span_note( - span, - &format!("method `{}` has generic type parameters", - method.name.user_string(tcx))); - } - } - } -} - -pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - span: Span, - object_trait: &ty::TyTrait<'tcx>, - referent_ty: Ty<'tcx>) - -> ty::PolyTraitRef<'tcx> -{ - // We can only make objects from sized types. - fcx.register_builtin_bound( - referent_ty, - ty::BoundSized, - traits::ObligationCause::new(span, fcx.body_id, traits::ObjectSized)); - - // This is just for better error reporting. Kinda goofy. The object type stuff - // needs some refactoring so there is a more convenient type to pass around. - let object_trait_ty = - ty::mk_trait(fcx.tcx(), - object_trait.principal.clone(), - object_trait.bounds.clone()); - - debug!("register_object_cast_obligations: referent_ty={} object_trait_ty={}", - referent_ty.repr(fcx.tcx()), - object_trait_ty.repr(fcx.tcx())); - - let cause = ObligationCause::new(span, - fcx.body_id, - traits::ObjectCastObligation(object_trait_ty)); - - // Create the obligation for casting from T to Trait. - let object_trait_ref = - object_trait.principal_trait_ref_with_self_ty(fcx.tcx(), referent_ty); - let object_obligation = - Obligation::new(cause.clone(), object_trait_ref.as_predicate()); - fcx.register_predicate(object_obligation); - - // Create additional obligations for all the various builtin - // bounds attached to the object cast. (In other words, if the - // object type is Foo+Send, this would create an obligation - // for the Send check.) - for builtin_bound in &object_trait.bounds.builtin_bounds { - fcx.register_builtin_bound( - referent_ty, - builtin_bound, - cause.clone()); - } - - // Create obligations for the projection predicates. - let projection_bounds = - object_trait.projection_bounds_with_self_ty(fcx.tcx(), referent_ty); - for projection_bound in &projection_bounds { - let projection_obligation = - Obligation::new(cause.clone(), projection_bound.as_predicate()); - fcx.register_predicate(projection_obligation); - } - - object_trait_ref -} - -pub fn select_all_fcx_obligations_and_apply_defaults(fcx: &FnCtxt) { - debug!("select_all_fcx_obligations_and_apply_defaults"); - - select_fcx_obligations_where_possible(fcx); - fcx.default_type_parameters(); - select_fcx_obligations_where_possible(fcx); -} - -pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) { - debug!("select_all_fcx_obligations_or_error"); - - // upvar inference should have ensured that all deferred call - // resolutions are handled by now. - assert!(fcx.inh.deferred_call_resolutions.borrow().is_empty()); - - select_all_fcx_obligations_and_apply_defaults(fcx); - let mut fulfillment_cx = fcx.inh.fulfillment_cx.borrow_mut(); - let r = fulfillment_cx.select_all_or_error(fcx.infcx(), fcx); - match r { - Ok(()) => { } - Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); } - } -} - -/// Select as many obligations as we can at present. -pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt) -{ - match - fcx.inh.fulfillment_cx - .borrow_mut() - .select_where_possible(fcx.infcx(), fcx) - { - Ok(()) => { } - Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); } - } -} - -/// Try to select any fcx obligation that we haven't tried yet, in an effort to improve inference. -/// You could just call `select_fcx_obligations_where_possible` except that it leads to repeated -/// work. -pub fn select_new_fcx_obligations(fcx: &FnCtxt) { - match - fcx.inh.fulfillment_cx - .borrow_mut() - .select_new_obligations(fcx.infcx(), fcx) - { - Ok(()) => { } - Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); } - } -} diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index c2209ba2dc6..79736c08f37 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -9,7 +9,7 @@ // except according to those terms. use astconv::AstConv; -use check::{FnCtxt, Inherited, blank_fn_ctxt, vtable, regionck}; +use check::{FnCtxt, Inherited, blank_fn_ctxt, regionck}; use constrained_type_params::{identify_constrained_type_params, Parameter}; use CrateCtxt; use middle::region; @@ -151,7 +151,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { let inh = Inherited::new(ccx.tcx, param_env); let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(type_scheme.ty), item.id); f(self, &fcx); - vtable::select_all_fcx_obligations_or_error(&fcx); + fcx.select_all_obligations_or_error(); regionck::regionck_item(&fcx, item); } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 4dc1596b1ff..c6e0bb676f7 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -16,7 +16,9 @@ // mappings. That mapping code resides here. +use middle::lang_items::UnsizeTraitLangItem; use middle::subst::{self, Subst}; +use middle::traits; use middle::ty::RegionEscape; use middle::ty::{ImplContainer, ImplOrTraitItemId, ConstTraitItemId}; use middle::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment}; @@ -28,8 +30,7 @@ use middle::ty::{ty_uint, ty_closure, ty_uniq, ty_bare_fn}; use middle::ty::ty_projection; use middle::ty; use CrateCtxt; -use middle::infer::InferCtxt; -use middle::infer::new_infer_ctxt; +use middle::infer::{self, InferCtxt, new_infer_ctxt}; use std::cell::RefCell; use std::rc::Rc; use syntax::ast::{Crate, DefId}; @@ -133,6 +134,10 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { // Check to make sure implementations of `Copy` are legal. self.check_implementations_of_copy(); + + // Check to make sure implementations of `CoerceUnsized` are legal + // and collect the necessary information from them. + self.check_implementations_of_coerce_unsized(); } fn check_implementation(&self, item: &Item, opt_trait: Option<&TraitRef>) { @@ -419,6 +424,169 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } }); } + + /// Process implementations of the built-in trait `CoerceUnsized`. + fn check_implementations_of_coerce_unsized(&self) { + let tcx = self.crate_context.tcx; + let coerce_unsized_trait = match tcx.lang_items.coerce_unsized_trait() { + Some(id) => id, + None => return, + }; + let unsize_trait = match tcx.lang_items.require(UnsizeTraitLangItem) { + Ok(id) => id, + Err(err) => { + tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err)); + } + }; + + let trait_impls = match tcx.trait_impls + .borrow() + .get(&coerce_unsized_trait) + .cloned() { + None => { + debug!("check_implementations_of_coerce_unsized(): no types \ + with implementations of `CoerceUnsized` found"); + return + } + Some(found_impls) => found_impls + }; + + // Clone first to avoid a double borrow error. + let trait_impls = trait_impls.borrow().clone(); + + for &impl_did in &trait_impls { + debug!("check_implementations_of_coerce_unsized: impl_did={}", + impl_did.repr(tcx)); + + if impl_did.krate != ast::LOCAL_CRATE { + debug!("check_implementations_of_coerce_unsized(): impl not \ + in this crate"); + continue + } + + let source = self.get_self_type_for_implementation(impl_did).ty; + let trait_ref = ty::impl_id_to_trait_ref(self.crate_context.tcx, + impl_did.node); + let target = *trait_ref.substs.types.get(subst::TypeSpace, 0); + debug!("check_implementations_of_coerce_unsized: {} -> {} (bound)", + source.repr(tcx), target.repr(tcx)); + + let span = tcx.map.span(impl_did.node); + let param_env = ParameterEnvironment::for_item(tcx, impl_did.node); + let source = source.subst(tcx, ¶m_env.free_substs); + let target = target.subst(tcx, ¶m_env.free_substs); + assert!(!source.has_escaping_regions()); + + debug!("check_implementations_of_coerce_unsized: {} -> {} (free)", + source.repr(tcx), target.repr(tcx)); + + let infcx = new_infer_ctxt(tcx); + + let check_mutbl = |mt_a: ty::mt<'tcx>, mt_b: ty::mt<'tcx>, + mk_ptr: &Fn(Ty<'tcx>) -> Ty<'tcx>| { + if (mt_a.mutbl, mt_b.mutbl) == (ast::MutImmutable, ast::MutMutable) { + infcx.report_mismatched_types(span, mk_ptr(mt_b.ty), + target, &ty::terr_mutability); + } + (mt_a.ty, mt_b.ty, unsize_trait, None) + }; + let (source, target, trait_def_id, kind) = match (&source.sty, &target.sty) { + (&ty::ty_uniq(a), &ty::ty_uniq(b)) => (a, b, unsize_trait, None), + + (&ty::ty_rptr(r_a, mt_a), &ty::ty_rptr(r_b, mt_b)) => { + infer::mk_subr(&infcx, infer::RelateObjectBound(span), *r_b, *r_a); + check_mutbl(mt_a, mt_b, &|ty| ty::mk_imm_rptr(tcx, r_b, ty)) + } + + (&ty::ty_rptr(_, mt_a), &ty::ty_ptr(mt_b)) | + (&ty::ty_ptr(mt_a), &ty::ty_ptr(mt_b)) => { + check_mutbl(mt_a, mt_b, &|ty| ty::mk_imm_ptr(tcx, ty)) + } + + (&ty::ty_struct(def_id_a, substs_a), &ty::ty_struct(def_id_b, substs_b)) => { + if def_id_a != def_id_b { + let source_path = ty::item_path_str(tcx, def_id_a); + let target_path = ty::item_path_str(tcx, def_id_b); + span_err!(tcx.sess, span, E0373, + "the trait `CoerceUnsized` may only be implemented \ + for a coercion between structures with the same \ + definition; expected {}, found {}", + source_path, target_path); + continue; + } + + let origin = infer::Misc(span); + let fields = ty::lookup_struct_fields(tcx, def_id_a); + let diff_fields = fields.iter().enumerate().filter_map(|(i, f)| { + let ty = ty::lookup_field_type_unsubstituted(tcx, def_id_a, f.id); + let (a, b) = (ty.subst(tcx, substs_a), ty.subst(tcx, substs_b)); + if infcx.sub_types(false, origin, b, a).is_ok() { + None + } else { + Some((i, a, b)) + } + }).collect::>(); + + if diff_fields.is_empty() { + span_err!(tcx.sess, span, E0374, + "the trait `CoerceUnsized` may only be implemented \ + for a coercion between structures with one field \ + being coerced, none found"); + continue; + } else if diff_fields.len() > 1 { + span_err!(tcx.sess, span, E0375, + "the trait `CoerceUnsized` may only be implemented \ + for a coercion between structures with one field \ + being coerced, but {} fields need coercions: {}", + diff_fields.len(), diff_fields.iter().map(|&(i, a, b)| { + let name = fields[i].name; + format!("{} ({} to {})", + if name == token::special_names::unnamed_field { + i.to_string() + } else { + token::get_name(name).to_string() + }, + a.repr(tcx), + b.repr(tcx)) + }).collect::>().connect(", ")); + continue; + } + + let (i, a, b) = diff_fields[0]; + let kind = ty::CustomCoerceUnsized::Struct(i); + (a, b, coerce_unsized_trait, Some(kind)) + } + + _ => { + span_err!(tcx.sess, span, E0376, + "the trait `CoerceUnsized` may only be implemented \ + for a coercion between structures"); + continue; + } + }; + + let mut fulfill_cx = traits::FulfillmentContext::new(); + + // Register an obligation for `A: Trait`. + let cause = traits::ObligationCause::misc(span, impl_did.node); + let predicate = traits::predicate_for_trait_def(tcx, cause, trait_def_id, + 0, source, vec![target]); + fulfill_cx.register_predicate_obligation(&infcx, predicate); + + // Check that all transitive obligations are satisfied. + if let Err(errors) = fulfill_cx.select_all_or_error(&infcx, ¶m_env) { + traits::report_fulfillment_errors(&infcx, &errors); + } + + // Finally, resolve all regions. This catches wily misuses of lifetime + // parameters. + infcx.resolve_regions_and_report_errors(impl_did.node); + + if let Some(kind) = kind { + tcx.custom_coerce_unsized_kinds.borrow_mut().insert(impl_did, kind); + } + } + } } fn enforce_trait_manually_implementable(tcx: &ty::ctxt, sp: Span, trait_def_id: ast::DefId) { diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index b450e6b398a..c75a0d816a8 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -316,12 +316,17 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { } } - // Disallow *all* explicit impls of `Sized` for now. + // Disallow *all* explicit impls of `Sized` and `Unsize` for now. if Some(trait_def_id) == self.tcx.lang_items.sized_trait() { span_err!(self.tcx.sess, item.span, E0322, "explicit impls for the `Sized` trait are not permitted"); return; } + if Some(trait_def_id) == self.tcx.lang_items.unsize_trait() { + span_err!(self.tcx.sess, item.span, E0323, + "explicit impls for the `Unsize` trait are not permitted"); + return; + } } ast::ItemDefaultImpl(..) => { // "Trait" impl diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index f9565d528e8..ac10a4e7121 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -445,10 +445,20 @@ register_diagnostics! { E0325, // implemented an associated type when another trait item expected E0326, // associated const implemented with different type from trait E0327, // referred to method instead of constant in match pattern + E0328, // cannot implement Unsize explicitly E0366, // dropck forbid specialization to concrete type or region E0367, // dropck forbid specialization to predicate not in struct/enum E0368, // binary operation `=` cannot be applied to types E0369, // binary operation `` cannot be applied to types E0371, // impl Trait for Trait is illegal - E0372 // impl Trait for Trait where Trait is not object safe + E0372, // impl Trait for Trait where Trait is not object safe + E0373, // the trait `CoerceUnsized` may only be implemented for a coercion + // between structures with the same definition + E0374, // the trait `CoerceUnsized` may only be implemented for a coercion + // between structures with one field being coerced, none found + E0375, // the trait `CoerceUnsized` may only be implemented for a coercion + // between structures with one field being coerced, but multiple + // fields need coercions + E0376 // the trait `CoerceUnsized` may only be implemented for a coercion + // between structures } diff --git a/src/test/compile-fail/destructure-trait-ref.rs b/src/test/compile-fail/destructure-trait-ref.rs index 4161cce2843..3f455e148a0 100644 --- a/src/test/compile-fail/destructure-trait-ref.rs +++ b/src/test/compile-fail/destructure-trait-ref.rs @@ -35,7 +35,7 @@ fn main() { // n == m let &x = &1 as &T; //~ ERROR type `&T` cannot be dereferenced let &&x = &(&1 as &T); //~ ERROR type `&T` cannot be dereferenced - let box x = box 1 as Box; //~ ERROR type `Box` cannot be dereferenced + let box x = box 1 as Box; //~ ERROR the trait `core::marker::Sized` is not implemented // n > m let &&x = &1 as &T; diff --git a/src/test/compile-fail/dst-bad-coercions.rs b/src/test/compile-fail/dst-bad-coercions.rs index b30eada162b..b7a07e48799 100644 --- a/src/test/compile-fail/dst-bad-coercions.rs +++ b/src/test/compile-fail/dst-bad-coercions.rs @@ -33,18 +33,4 @@ pub fn main() { let x: &mut T = &S; //~ ERROR mismatched types let x: *mut T = &S; //~ ERROR mismatched types let x: *mut S = &S; //~ ERROR mismatched types - - // The below four sets of tests test that we cannot implicitly deref a *-ptr - // during a coercion. - let x: *const S = &S; - let y: *const T = x; //~ ERROR mismatched types - - let x: *mut S = &mut S; - let y: *mut T = x; //~ ERROR mismatched types - - let x: *const Foo = &Foo {f: S}; - let y: *const Foo = x; //~ ERROR mismatched types - - let x: *mut Foo = &mut Foo {f: S}; - let y: *mut Foo = x; //~ ERROR mismatched types } diff --git a/src/test/compile-fail/issue-19692.rs b/src/test/compile-fail/issue-19692.rs index 7794c34a04b..7b84ba0343a 100644 --- a/src/test/compile-fail/issue-19692.rs +++ b/src/test/compile-fail/issue-19692.rs @@ -12,7 +12,7 @@ struct Homura; fn akemi(homura: Homura) { let Some(ref madoka) = Some(homura.kaname()); //~ ERROR does not implement any method - madoka.clone(); + madoka.clone(); //~ ERROR the type of this value must be known in this context } fn main() { } diff --git a/src/test/compile-fail/issue-20261.rs b/src/test/compile-fail/issue-20261.rs index 33e00f9a823..42fd856ad87 100644 --- a/src/test/compile-fail/issue-20261.rs +++ b/src/test/compile-fail/issue-20261.rs @@ -12,6 +12,5 @@ fn main() { for (ref i,) in [].iter() { //~ ERROR: type mismatch resolving i.clone(); //~^ ERROR: the type of this value must be known in this context - //~| ERROR: reached the recursion limit while auto-dereferencing } } diff --git a/src/test/compile-fail/issue-22034.rs b/src/test/compile-fail/issue-22034.rs index c084a94d55e..8b258180e83 100644 --- a/src/test/compile-fail/issue-22034.rs +++ b/src/test/compile-fail/issue-22034.rs @@ -14,6 +14,7 @@ fn main() { let ptr: *mut () = 0 as *mut _; let _: &mut Fn() = unsafe { &mut *(ptr as *mut Fn()) - //~^ ERROR illegal cast + //~^ ERROR the trait `core::ops::Fn<()>` is not implemented + //~| ERROR the trait `core::ops::FnOnce<()>` is not implemented }; } diff --git a/src/test/compile-fail/object-lifetime-default-elision.rs b/src/test/compile-fail/object-lifetime-default-elision.rs index 4fba45e2a66..75ee0bdc9c7 100644 --- a/src/test/compile-fail/object-lifetime-default-elision.rs +++ b/src/test/compile-fail/object-lifetime-default-elision.rs @@ -81,7 +81,7 @@ fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait { // which fails to type check. ss - //~^ ERROR lifetime of the source pointer does not outlive lifetime bound + //~^ ERROR lifetime bound not satisfied //~| ERROR cannot infer } diff --git a/src/test/compile-fail/object-lifetime-default-from-box-error.rs b/src/test/compile-fail/object-lifetime-default-from-box-error.rs index 7fae530984f..dd94dfe1e08 100644 --- a/src/test/compile-fail/object-lifetime-default-from-box-error.rs +++ b/src/test/compile-fail/object-lifetime-default-from-box-error.rs @@ -25,7 +25,7 @@ fn load(ss: &mut SomeStruct) -> Box { // `Box` defaults to a `'static` bound, so this return // is illegal. - ss.r //~ ERROR lifetime of the source pointer does not outlive lifetime bound + ss.r //~ ERROR lifetime bound not satisfied } fn store(ss: &mut SomeStruct, b: Box) { @@ -38,7 +38,7 @@ fn store(ss: &mut SomeStruct, b: Box) { fn store1<'b>(ss: &mut SomeStruct, b: Box) { // Here we override the lifetimes explicitly, and so naturally we get an error. - ss.r = b; //~ ERROR lifetime of the source pointer does not outlive lifetime bound + ss.r = b; //~ ERROR lifetime bound not satisfied } fn main() { diff --git a/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs index 10b883d4dc8..c5cf43e355d 100644 --- a/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs +++ b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs @@ -27,7 +27,7 @@ fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box { fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box { // A outlives 'a AND 'b...but not 'c. - box v as Box //~ ERROR lifetime of the source pointer does not outlive + box v as Box //~ ERROR lifetime bound not satisfied } fn main() { diff --git a/src/test/compile-fail/regions-trait-object-subtyping.rs b/src/test/compile-fail/regions-trait-object-subtyping.rs index f3722690ef8..b4e527972e4 100644 --- a/src/test/compile-fail/regions-trait-object-subtyping.rs +++ b/src/test/compile-fail/regions-trait-object-subtyping.rs @@ -22,7 +22,7 @@ fn foo2<'a:'b,'b>(x: &'b mut (Dummy+'a)) -> &'b mut (Dummy+'b) { fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy { // Without knowing 'a:'b, we can't coerce - x //~ ERROR lifetime of the source pointer does not outlive + x //~ ERROR lifetime bound not satisfied //~^ ERROR cannot infer } From 7d953538d10c4a31300afd27f73563adb056beab Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 16 Apr 2015 14:36:47 +1200 Subject: [PATCH 2/7] Make Rc DST-compatible --- src/liballoc/rc.rs | 389 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 382 insertions(+), 7 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index a1b5e6e6baf..4e8a7e8bfc9 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -159,7 +159,7 @@ use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering}; use core::default::Default; use core::fmt; use core::hash::{Hasher, Hash}; -use core::marker; +use core::marker::{self, Sized}; use core::mem::{self, min_align_of, size_of, forget}; use core::nonzero::NonZero; use core::ops::{Deref, Drop}; @@ -170,17 +170,36 @@ use core::result::Result; use core::result::Result::{Ok, Err}; use core::intrinsics::assume; +#[cfg(not(stage0))] +use core::intrinsics::drop_in_place; +#[cfg(not(stage0))] +use core::marker::Unsize; +#[cfg(not(stage0))] +use core::mem::{min_align_of_val, size_of_val}; +#[cfg(not(stage0))] +use core::ops::CoerceUnsized; + use heap::deallocate; +#[cfg(stage0)] struct RcBox { strong: Cell, weak: Cell, - value: T + value: T, } +#[cfg(not(stage0))] +struct RcBox { + strong: Cell, + weak: Cell, + value: T, +} + + /// A reference-counted pointer type over an immutable value. /// /// See the [module level documentation](./index.html) for more details. +#[cfg(stage0)] #[unsafe_no_drop_flag] #[stable(feature = "rust1", since = "1.0.0")] pub struct Rc { @@ -188,11 +207,30 @@ pub struct Rc { // accesses of the contained type via Deref _ptr: NonZero<*mut RcBox>, } +#[cfg(not(stage0))] +#[unsafe_no_drop_flag] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Rc { + // FIXME #12808: strange names to try to avoid interfering with field + // accesses of the contained type via Deref + _ptr: NonZero<*mut RcBox>, +} +#[cfg(stage0)] impl !marker::Send for Rc {} +#[cfg(not(stage0))] +impl !marker::Send for Rc {} + +#[cfg(stage0)] impl !marker::Sync for Rc {} +#[cfg(not(stage0))] +impl !marker::Sync for Rc {} + +#[cfg(not(stage0))] // SNAP c64d671 +impl, U: ?Sized> CoerceUnsized> for Rc {} + impl Rc { /// Constructs a new `Rc`. /// @@ -212,14 +250,39 @@ impl Rc { // the allocation while the strong destructor is running, even // if the weak pointer is stored inside the strong one. _ptr: NonZero::new(boxed::into_raw(box RcBox { - value: value, strong: Cell::new(1), - weak: Cell::new(1) + weak: Cell::new(1), + value: value })), } } } +} +#[cfg(not(stage0))] +impl Rc { + /// Downgrades the `Rc` to a `Weak` reference. + /// + /// # Examples + /// + /// ``` + /// # #![feature(alloc)] + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// let weak_five = five.downgrade(); + /// ``` + #[unstable(feature = "alloc", + reason = "Weak pointers may not belong in this module")] + pub fn downgrade(&self) -> Weak { + self.inc_weak(); + Weak { _ptr: self._ptr } + } +} + +#[cfg(stage0)] +impl Rc { /// Downgrades the `Rc` to a `Weak` reference. /// /// # Examples @@ -241,14 +304,24 @@ impl Rc { } /// Get the number of weak references to this value. +#[cfg(stage0)] #[inline] #[unstable(feature = "alloc")] pub fn weak_count(this: &Rc) -> usize { this.weak() - 1 } +#[cfg(not(stage0))] +#[inline] +#[unstable(feature = "alloc")] +pub fn weak_count(this: &Rc) -> usize { this.weak() - 1 } /// Get the number of strong references to this value. +#[cfg(stage0)] #[inline] #[unstable(feature = "alloc")] pub fn strong_count(this: &Rc) -> usize { this.strong() } +#[cfg(not(stage0))] +#[inline] +#[unstable(feature = "alloc")] +pub fn strong_count(this: &Rc) -> usize { this.strong() } /// Returns true if there are no other `Rc` or `Weak` values that share the /// same inner value. @@ -365,6 +438,7 @@ impl Rc { } } +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl Deref for Rc { type Target = T; @@ -374,7 +448,19 @@ impl Deref for Rc { &self.inner().value } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Deref for Rc { + type Target = T; + #[inline(always)] + fn deref(&self) -> &T { + &self.inner().value + } +} + +#[cfg(stage0)] // SNAP c64d671 +#[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Rc { /// Drops the `Rc`. @@ -425,6 +511,61 @@ impl Drop for Rc { } } +#[cfg(not(stage0))] // SNAP c64d671 +#[unsafe_destructor] +#[stable(feature = "rust1", since = "1.0.0")] +impl Drop for Rc { + /// Drops the `Rc`. + /// + /// This will decrement the strong reference count. If the strong reference + /// count becomes zero and the only other references are `Weak` ones, + /// `drop`s the inner value. + /// + /// # Examples + /// + /// ``` + /// # #![feature(alloc)] + /// use std::rc::Rc; + /// + /// { + /// let five = Rc::new(5); + /// + /// // stuff + /// + /// drop(five); // explicit drop + /// } + /// { + /// let five = Rc::new(5); + /// + /// // stuff + /// + /// } // implicit drop + /// ``` + fn drop(&mut self) { + unsafe { + let ptr = *self._ptr; + if !(*(&ptr as *const _ as *const *const ())).is_null() { + self.dec_strong(); + if self.strong() == 0 { + // destroy the contained object + drop_in_place(&mut (*ptr).value); + + // remove the implicit "strong weak" pointer now that we've + // destroyed the contents. + self.dec_weak(); + + if self.weak() == 0 { + deallocate(ptr as *mut u8, + size_of_val(&*ptr), + min_align_of_val(&*ptr)) + } + } + } + } + } +} + +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Rc { @@ -449,6 +590,31 @@ impl Clone for Rc { Rc { _ptr: self._ptr } } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Rc { + + /// Makes a clone of the `Rc`. + /// + /// When you clone an `Rc`, it will create another pointer to the data and + /// increase the strong reference counter. + /// + /// # Examples + /// + /// ``` + /// # #![feature(alloc)] + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// five.clone(); + /// ``` + #[inline] + fn clone(&self) -> Rc { + self.inc_strong(); + Rc { _ptr: self._ptr } + } +} #[stable(feature = "rust1", since = "1.0.0")] impl Default for Rc { @@ -610,27 +776,50 @@ impl Ord for Rc { fn cmp(&self, other: &Rc) -> Ordering { (**self).cmp(&**other) } } -// FIXME (#18248) Make `T` `Sized?` +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl Hash for Rc { fn hash(&self, state: &mut H) { (**self).hash(state); } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Hash for Rc { + fn hash(&self, state: &mut H) { + (**self).hash(state); + } +} +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Rc { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&**self, f) } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for Rc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Rc { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Rc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Pointer for Rc { @@ -645,6 +834,7 @@ impl fmt::Pointer for Rc { /// dropped. /// /// See the [module level documentation](./index.html) for more. +#[cfg(stage0)] #[unsafe_no_drop_flag] #[unstable(feature = "alloc", reason = "Weak pointers may not belong in this module.")] @@ -653,12 +843,28 @@ pub struct Weak { // field accesses of the contained type via Deref _ptr: NonZero<*mut RcBox>, } +#[cfg(not(stage0))] +#[unsafe_no_drop_flag] +#[unstable(feature = "alloc", + reason = "Weak pointers may not belong in this module.")] +pub struct Weak { + // FIXME #12808: strange names to try to avoid interfering with + // field accesses of the contained type via Deref + _ptr: NonZero<*mut RcBox>, +} +#[cfg(stage0)] impl !marker::Send for Weak {} +#[cfg(not(stage0))] +impl !marker::Send for Weak {} +#[cfg(stage0)] impl !marker::Sync for Weak {} +#[cfg(not(stage0))] +impl !marker::Sync for Weak {} +#[cfg(stage0)] #[unstable(feature = "alloc", reason = "Weak pointers may not belong in this module.")] impl Weak { @@ -691,7 +897,42 @@ impl Weak { } } } +#[cfg(not(stage0))] +#[unstable(feature = "alloc", + reason = "Weak pointers may not belong in this module.")] +impl Weak { + /// Upgrades a weak reference to a strong reference. + /// + /// Upgrades the `Weak` reference to an `Rc`, if possible. + /// + /// Returns `None` if there were no strong references and the data was + /// destroyed. + /// + /// # Examples + /// + /// ``` + /// # #![feature(alloc)] + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// let weak_five = five.downgrade(); + /// + /// let strong_five: Option> = weak_five.upgrade(); + /// ``` + pub fn upgrade(&self) -> Option> { + if self.strong() == 0 { + None + } else { + self.inc_strong(); + Some(Rc { _ptr: self._ptr }) + } + } +} + +#[cfg(stage0)] // SNAP c64d671 +#[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Weak { /// Drops the `Weak`. @@ -736,6 +977,53 @@ impl Drop for Weak { } } +#[cfg(not(stage0))] // SNAP c64d671 +#[unsafe_destructor] +#[stable(feature = "rust1", since = "1.0.0")] +impl Drop for Weak { + /// Drops the `Weak`. + /// + /// This will decrement the weak reference count. + /// + /// # Examples + /// + /// ``` + /// # #![feature(alloc)] + /// use std::rc::Rc; + /// + /// { + /// let five = Rc::new(5); + /// let weak_five = five.downgrade(); + /// + /// // stuff + /// + /// drop(weak_five); // explicit drop + /// } + /// { + /// let five = Rc::new(5); + /// let weak_five = five.downgrade(); + /// + /// // stuff + /// + /// } // implicit drop + /// ``` + fn drop(&mut self) { + unsafe { + let ptr = *self._ptr; + if !(*(&ptr as *const _ as *const *const ())).is_null() { + self.dec_weak(); + // the weak count starts at 1, and will only go to zero if all + // the strong pointers have disappeared. + if self.weak() == 0 { + deallocate(ptr as *mut u8, size_of_val(&*ptr), + min_align_of_val(&*ptr)) + } + } + } + } +} + +#[cfg(stage0)] #[unstable(feature = "alloc", reason = "Weak pointers may not belong in this module.")] impl Clone for Weak { @@ -760,14 +1048,48 @@ impl Clone for Weak { Weak { _ptr: self._ptr } } } +#[cfg(not(stage0))] +#[unstable(feature = "alloc", + reason = "Weak pointers may not belong in this module.")] +impl Clone for Weak { + /// Makes a clone of the `Weak`. + /// + /// This increases the weak reference count. + /// + /// # Examples + /// + /// ``` + /// # #![feature(alloc)] + /// use std::rc::Rc; + /// + /// let weak_five = Rc::new(5).downgrade(); + /// + /// weak_five.clone(); + /// ``` + #[inline] + fn clone(&self) -> Weak { + self.inc_weak(); + Weak { _ptr: self._ptr } + } +} + +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Weak { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "(Weak)") } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Weak { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "(Weak)") + } +} +#[cfg(stage0)] #[doc(hidden)] trait RcBoxPtr { fn inner(&self) -> &RcBox; @@ -790,7 +1112,31 @@ trait RcBoxPtr { #[inline] fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); } } +#[cfg(not(stage0))] +#[doc(hidden)] +trait RcBoxPtr { + fn inner(&self) -> &RcBox; + #[inline] + fn strong(&self) -> usize { self.inner().strong.get() } + + #[inline] + fn inc_strong(&self) { self.inner().strong.set(self.strong() + 1); } + + #[inline] + fn dec_strong(&self) { self.inner().strong.set(self.strong() - 1); } + + #[inline] + fn weak(&self) -> usize { self.inner().weak.get() } + + #[inline] + fn inc_weak(&self) { self.inner().weak.set(self.weak() + 1); } + + #[inline] + fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); } +} + +#[cfg(stage0)] impl RcBoxPtr for Rc { #[inline(always)] fn inner(&self) -> &RcBox { @@ -799,12 +1145,27 @@ impl RcBoxPtr for Rc { // the contract anyway. // This allows the null check to be elided in the destructor if we // manipulated the reference count in the same function. - assume(!self._ptr.is_null()); + assume(!(*(&self._ptr as *const _ as *const *const ())).is_null()); + &(**self._ptr) + } + } +} +#[cfg(not(stage0))] +impl RcBoxPtr for Rc { + #[inline(always)] + fn inner(&self) -> &RcBox { + unsafe { + // Safe to assume this here, as if it weren't true, we'd be breaking + // the contract anyway. + // This allows the null check to be elided in the destructor if we + // manipulated the reference count in the same function. + assume(!(*(&self._ptr as *const _ as *const *const ())).is_null()); &(**self._ptr) } } } +#[cfg(stage0)] impl RcBoxPtr for Weak { #[inline(always)] fn inner(&self) -> &RcBox { @@ -813,7 +1174,21 @@ impl RcBoxPtr for Weak { // the contract anyway. // This allows the null check to be elided in the destructor if we // manipulated the reference count in the same function. - assume(!self._ptr.is_null()); + assume(!(*(&self._ptr as *const _ as *const *const ())).is_null()); + &(**self._ptr) + } + } +} +#[cfg(not(stage0))] +impl RcBoxPtr for Weak { + #[inline(always)] + fn inner(&self) -> &RcBox { + unsafe { + // Safe to assume this here, as if it weren't true, we'd be breaking + // the contract anyway. + // This allows the null check to be elided in the destructor if we + // manipulated the reference count in the same function. + assume(!(*(&self._ptr as *const _ as *const *const ())).is_null()); &(**self._ptr) } } From 03d4d5f80ed1d9e168869bdb244e4fef67b7d3d0 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 20 Apr 2015 10:52:26 +1200 Subject: [PATCH 3/7] Fix a bunch of bugs * segfault due to not copying drop flag when coercing * fat pointer casts * segfault due to not checking drop flag properly * debuginfo for DST smart pointers * unreachable code in drop glue --- src/liballoc/rc.rs | 6 ++-- src/librustc/middle/ty.rs | 3 +- src/librustc_trans/trans/adt.rs | 14 +++++--- src/librustc_trans/trans/expr.rs | 49 +++++++++++++++++---------- src/librustc_trans/trans/glue.rs | 13 +++---- src/librustc_trans/trans/machine.rs | 3 +- src/librustc_typeck/check/cast.rs | 17 +++++----- src/test/compile-fail/fat-ptr-cast.rs | 12 +++---- src/test/compile-fail/issue-22289.rs | 2 +- src/test/run-pass/fat-ptr-cast.rs | 49 +++++++++++++++++++++++++++ 10 files changed, 114 insertions(+), 54 deletions(-) create mode 100644 src/test/run-pass/fat-ptr-cast.rs diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 4e8a7e8bfc9..837cf590024 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -544,7 +544,8 @@ impl Drop for Rc { fn drop(&mut self) { unsafe { let ptr = *self._ptr; - if !(*(&ptr as *const _ as *const *const ())).is_null() { + if !(*(&ptr as *const _ as *const *const ())).is_null() && + ptr as usize != mem::POST_DROP_USIZE { self.dec_strong(); if self.strong() == 0 { // destroy the contained object @@ -1010,7 +1011,8 @@ impl Drop for Weak { fn drop(&mut self) { unsafe { let ptr = *self._ptr; - if !(*(&ptr as *const _ as *const *const ())).is_null() { + if !(*(&ptr as *const _ as *const *const ())).is_null() && + ptr as usize != mem::POST_DROP_USIZE { self.dec_weak(); // the weak count starts at 1, and will only go to zero if all // the strong pointers have disappeared. diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 961f8a79324..5a84edd3cdf 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -5606,8 +5606,7 @@ impl DtorKind { } } -/* If struct_id names a struct with a dtor, return Some(the dtor's id). - Otherwise return none. */ +/* If struct_id names a struct with a dtor. */ pub fn ty_dtor(cx: &ctxt, struct_id: DefId) -> DtorKind { match cx.destructor_for_type.borrow().get(&struct_id) { Some(&method_def_id) => { diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 001de615fb1..17c9fa24818 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -141,7 +141,8 @@ pub fn represent_node<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// Decides how to represent a given type. pub fn represent_type<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, - t: Ty<'tcx>) -> Rc> { + t: Ty<'tcx>) + -> Rc> { debug!("Representing: {}", ty_to_string(cx.tcx(), t)); match cx.adt_reprs().borrow().get(&t) { Some(repr) => return repr.clone(), @@ -216,7 +217,9 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }).collect::>(); let packed = ty::lookup_packed(cx.tcx(), def_id); let dtor = ty::ty_dtor(cx.tcx(), def_id).has_drop_flag(); - if dtor { ftys.push(cx.tcx().dtor_type()); } + if dtor { + ftys.push(cx.tcx().dtor_type()); + } Univariant(mk_struct(cx, &ftys[..], packed, t), dtor_to_init_u8(dtor)) } @@ -517,8 +520,7 @@ fn mk_struct<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, -> Struct<'tcx> { let sized = tys.iter().all(|&ty| type_is_sized(cx.tcx(), ty)); let lltys : Vec = if sized { - tys.iter() - .map(|&ty| type_of::sizing_type_of(cx, ty)).collect() + tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect() } else { tys.iter().filter(|&ty| type_is_sized(cx.tcx(), *ty)) .map(|&ty| type_of::sizing_type_of(cx, ty)).collect() @@ -1060,7 +1062,9 @@ pub fn fold_variants<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, } /// Access the struct drop flag, if present. -pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, val: ValueRef) +pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, + r: &Repr<'tcx>, + val: ValueRef) -> datum::DatumBlock<'blk, 'tcx, datum::Expr> { let tcx = bcx.tcx(); diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 0343571562f..4018df0da47 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -58,7 +58,7 @@ use middle::check_const; use middle::def; use middle::lang_items::CoerceUnsizedTraitLangItem; use middle::mem_categorization::Typer; -use middle::subst::{Subst, Substs, VecPerParamSpace}; +use middle::subst::{Substs, VecPerParamSpace}; use middle::traits; use trans::{_match, adt, asm, base, callee, closure, consts, controlflow}; use trans::base::*; @@ -476,8 +476,8 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } // This can be extended to enums and tuples in the future. - // (&ty::ty_enum(def_id_a, substs_a), &ty::ty_enum(def_id_b, substs_b)) | - (&ty::ty_struct(def_id_a, substs_a), &ty::ty_struct(def_id_b, substs_b)) => { + // (&ty::ty_enum(def_id_a, _), &ty::ty_enum(def_id_b, _)) | + (&ty::ty_struct(def_id_a, _), &ty::ty_struct(def_id_b, _)) => { assert_eq!(def_id_a, def_id_b); // The target is already by-ref because it's to be written to. @@ -504,35 +504,41 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; let repr_source = adt::represent_type(bcx.ccx(), source.ty); + let src_fields = match &*repr_source { + &adt::Repr::Univariant(ref s, _) => &s.fields, + _ => bcx.sess().span_bug(span, + &format!("Non univariant struct? (repr_source: {:?})", + repr_source)), + }; let repr_target = adt::represent_type(bcx.ccx(), target.ty); - let fields = ty::lookup_struct_fields(bcx.tcx(), def_id_a); + let target_fields = match &*repr_target { + &adt::Repr::Univariant(ref s, _) => &s.fields, + _ => bcx.sess().span_bug(span, + &format!("Non univariant struct? (repr_target: {:?})", + repr_target)), + }; let coerce_index = match kind { ty::CustomCoerceUnsized::Struct(i) => i }; - assert!(coerce_index < fields.len()); + assert!(coerce_index < src_fields.len() && src_fields.len() == target_fields.len()); - for (i, field) in fields.iter().enumerate() { + let iter = src_fields.iter().zip(target_fields.iter()).enumerate(); + for (i, (src_ty, target_ty)) in iter { let ll_source = adt::trans_field_ptr(bcx, &repr_source, source.val, 0, i); let ll_target = adt::trans_field_ptr(bcx, &repr_target, target.val, 0, i); - let ty = ty::lookup_field_type_unsubstituted(bcx.tcx(), - def_id_a, - field.id); - let field_source = ty.subst(bcx.tcx(), substs_a); - let field_target = ty.subst(bcx.tcx(), substs_b); - // If this is the field we need to coerce, recurse on it. if i == coerce_index { coerce_unsized(bcx, span, - Datum::new(ll_source, field_source, + Datum::new(ll_source, src_ty, Rvalue::new(ByRef)), - Datum::new(ll_target, field_target, + Datum::new(ll_target, target_ty, Rvalue::new(ByRef))); } else { // Otherwise, simply copy the data from the source. - assert_eq!(field_source, field_target); - memcpy_ty(bcx, ll_target, ll_source, field_source); + assert_eq!(src_ty, target_ty); + memcpy_ty(bcx, ll_target, ll_source, src_ty); } } } @@ -2013,6 +2019,7 @@ fn float_cast(bcx: Block, #[derive(Copy, Clone, PartialEq, Debug)] pub enum cast_kind { cast_pointer, + cast_fat_ptr, cast_integral, cast_float, cast_enum, @@ -2027,7 +2034,7 @@ pub fn cast_type_kind<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> cast_kind { if type_is_sized(tcx, mt.ty) { cast_pointer } else { - cast_other + cast_fat_ptr } } ty::ty_bare_fn(..) => cast_pointer, @@ -2103,10 +2110,18 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let llexpr = datum.to_llscalarish(bcx); PtrToInt(bcx, llexpr, ll_t_out) } + (cast_fat_ptr, cast_integral) => { + let data_ptr = Load(bcx, get_dataptr(bcx, datum.val)); + PtrToInt(bcx, data_ptr, ll_t_out) + } (cast_pointer, cast_pointer) => { let llexpr = datum.to_llscalarish(bcx); PointerCast(bcx, llexpr, ll_t_out) } + (cast_fat_ptr, cast_pointer) => { + let data_ptr = Load(bcx, get_dataptr(bcx, datum.val)); + PointerCast(bcx, data_ptr, ll_t_out) + } (cast_enum, cast_integral) | (cast_enum, cast_float) => { let mut bcx = bcx; diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index fd1f22e1d9d..264957d3651 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -278,18 +278,14 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, - v0: ValueRef, + struct_data: ValueRef, dtor_did: ast::DefId, class_did: ast::DefId, substs: &subst::Substs<'tcx>) -> Block<'blk, 'tcx> { + assert!(type_is_sized(bcx.tcx(), t), "Precondition: caller must ensure t is sized"); + let repr = adt::represent_type(bcx.ccx(), t); - let struct_data = if type_is_sized(bcx.tcx(), t) { - v0 - } else { - let llval = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]); - Load(bcx, llval) - }; let drop_flag = unpack_datum!(bcx, adt::trans_drop_flag_ptr(bcx, &*repr, struct_data)); let loaded = load_ty(bcx, drop_flag.val, bcx.tcx().dtor_type()); let drop_flag_llty = type_of(bcx.fcx.ccx, bcx.tcx().dtor_type()); @@ -313,9 +309,8 @@ fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let drop_flag_dtor_needed = ICmp(bcx, llvm::IntEQ, loaded, init_val, DebugLoc::None); with_cond(bcx, drop_flag_dtor_needed, |cx| { - trans_struct_drop(cx, t, v0, dtor_did, class_did, substs) + trans_struct_drop(cx, t, struct_data, dtor_did, class_did, substs) }) - } pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, diff --git a/src/librustc_trans/trans/machine.rs b/src/librustc_trans/trans/machine.rs index ce37d38dc89..39bc547a1a7 100644 --- a/src/librustc_trans/trans/machine.rs +++ b/src/librustc_trans/trans/machine.rs @@ -101,7 +101,8 @@ pub fn llalign_of_min(cx: &CrateContext, ty: Type) -> llalign { pub fn llelement_offset(cx: &CrateContext, struct_ty: Type, element: usize) -> u64 { unsafe { - return llvm::LLVMOffsetOfElement(cx.td().lltd, struct_ty.to_ref(), + return llvm::LLVMOffsetOfElement(cx.td().lltd, + struct_ty.to_ref(), element as u32); } } diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index f0495436bc1..bfd159720c2 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -99,6 +99,7 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { let t_1_is_bare_fn = ty::type_is_bare_fn(t_1); let t_1_is_float = ty::type_is_floating_point(t_1); let t_1_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_1); + let t1_is_fat_ptr = fcx.type_is_fat_ptr(t_1, span); // casts to scalars other than `char` and `bare fn` are trivial let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn; @@ -170,18 +171,16 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { demand::coerce(fcx, e.span, t_1, &e); } } - } else if fcx.type_is_fat_ptr(t_e, span) != fcx.type_is_fat_ptr(t_1, span) { + } else if t1_is_fat_ptr { + // FIXME This should be allowed where the lefthandside is also a fat + // pointer and is the same kind of fat pointer, i.e., array to array, + // trait object to trait object. fcx.type_error_message(span, |actual| { - format!("illegal cast; cast to or from fat pointer: `{}` as `{}` \ - involving incompatible type.", - actual, fcx.infcx().ty_to_string(t_1)) + format!("cast to fat pointer: `{}` as `{}`", + actual, + fcx.infcx().ty_to_string(t_1)) }, t_e, None); } else if !(t_e_is_scalar && t_1_is_trivial) { - /* - If more type combinations should be supported than are - supported here, then file an enhancement issue and - record the issue number in this comment. - */ fcx.type_error_message(span, |actual| { format!("non-scalar cast: `{}` as `{}`", actual, diff --git a/src/test/compile-fail/fat-ptr-cast.rs b/src/test/compile-fail/fat-ptr-cast.rs index 381dff36b7d..415785a1174 100644 --- a/src/test/compile-fail/fat-ptr-cast.rs +++ b/src/test/compile-fail/fat-ptr-cast.rs @@ -15,17 +15,13 @@ pub trait Trait {} fn main() { let a: &[i32] = &[1, 2, 3]; let b: Box<[i32]> = Box::new([1, 2, 3]); - let p = a as *const [i32]; - let q = a.as_ptr(); a as usize; //~ ERROR illegal cast b as usize; //~ ERROR illegal cast - p as usize; //~ ERROR illegal cast - // #22955 - q as *const [i32]; //~ ERROR illegal cast + let a: usize = 42; + a as *const [i32]; //~ ERROR cast to fat pointer: `usize` as `*const [i32]` - // #21397 - let t: *mut (Trait + 'static) = 0 as *mut _; //~ ERROR illegal cast - let mut fail: *const str = 0 as *const str; //~ ERROR illegal cast + let a: *const u8 = &42; + a as *const [u8]; //~ ERROR cast to fat pointer: `*const u8` as `*const [u8]` } diff --git a/src/test/compile-fail/issue-22289.rs b/src/test/compile-fail/issue-22289.rs index 5adea183bc9..1fdc8735714 100644 --- a/src/test/compile-fail/issue-22289.rs +++ b/src/test/compile-fail/issue-22289.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - 0 as &std::any::Any; //~ ERROR illegal cast + 0 as &std::any::Any; //~ ERROR cast to fat pointer: `i32` as `&core::any::Any` } diff --git a/src/test/run-pass/fat-ptr-cast.rs b/src/test/run-pass/fat-ptr-cast.rs new file mode 100644 index 00000000000..b7513da99c8 --- /dev/null +++ b/src/test/run-pass/fat-ptr-cast.rs @@ -0,0 +1,49 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(core)] + +use std::mem; +use std::raw; + +trait Foo { + fn foo(&self) {} +} + +struct Bar; + +impl Foo for Bar {} + +fn main() { + // Test we can turn a fat pointer to array back into a thin pointer. + let a: *const [i32] = &[1, 2, 3]; + let b = a as *const [i32; 2]; + unsafe { + assert!(*b == [1, 2]); + } + + // Test conversion to an address (usize). + let a: *const [i32; 3] = &[1, 2, 3]; + let b: *const [i32] = a; + assert!(a as usize == b as usize); + + // And conversion to a void pointer/address for trait objects too. + let a: *mut Foo = &mut Bar; + let b = a as *mut (); + let c = a as usize; + + let d = unsafe { + let r: raw::TraitObject = mem::transmute(a); + r.data + }; + + assert!(b == d); + assert!(c == d as usize); +} From db1b14a194cbdbba813aeb4773ee7fa203a40fb1 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 20 Apr 2015 17:56:25 +1200 Subject: [PATCH 4/7] Tests for custom coercions --- src/test/run-pass/dst-coerce-custom.rs | 52 ++++++++++++++++++++++++++ src/test/run-pass/dst-coerce-rc.rs | 39 +++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 src/test/run-pass/dst-coerce-custom.rs create mode 100644 src/test/run-pass/dst-coerce-rc.rs diff --git a/src/test/run-pass/dst-coerce-custom.rs b/src/test/run-pass/dst-coerce-custom.rs new file mode 100644 index 00000000000..aa28ae00e27 --- /dev/null +++ b/src/test/run-pass/dst-coerce-custom.rs @@ -0,0 +1,52 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test a very simple custom DST coercion. + +#![feature(core)] + +use std::ops::CoerceUnsized; +use std::marker::Unsize; + +struct Bar { + x: *const T, +} + +impl, U: ?Sized> CoerceUnsized> for Bar {} + +trait Baz { + fn get(&self) -> i32; +} + +impl Baz for i32 { + fn get(&self) -> i32 { + *self + } +} + +fn main() { + // Arrays. + let a: Bar<[i32; 3]> = Bar { x: &[1, 2, 3] }; + // This is the actual coercion. + let b: Bar<[i32]> = a; + + unsafe { + assert_eq!((*b.x)[0], 1); + assert_eq!((*b.x)[1], 2); + assert_eq!((*b.x)[2], 3); + } + + // Trait objects. + let a: Bar = Bar { x: &42 }; + let b: Bar = a; + unsafe { + assert_eq!((*b.x).get(), 42); + } +} diff --git a/src/test/run-pass/dst-coerce-rc.rs b/src/test/run-pass/dst-coerce-rc.rs new file mode 100644 index 00000000000..32e7a6279c8 --- /dev/null +++ b/src/test/run-pass/dst-coerce-rc.rs @@ -0,0 +1,39 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test a very simple custom DST coercion. + +#![feature(core)] + +use std::rc::Rc; + +trait Baz { + fn get(&self) -> i32; +} + +impl Baz for i32 { + fn get(&self) -> i32 { + *self + } +} + +fn main() { + let a: Rc<[i32; 3]> = Rc::new([1, 2, 3]); + let b: Rc<[i32]> = a; + assert_eq!(b[0], 1); + assert_eq!(b[1], 2); + assert_eq!(b[2], 3); + + let a: Rc = Rc::new(42); + let b: Rc = a.clone(); + assert_eq!(b.get(), 42); + + let _c = b.clone(); +} From 5d4cce6cec7c0975263bbe6f4260167a772bfc89 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 12 May 2015 14:41:08 +1200 Subject: [PATCH 5/7] Rebasing --- src/liballoc/rc.rs | 4 -- src/libcore/cell.rs | 1 - src/libcore/ops.rs | 9 +++ src/libcoretest/cell.rs | 23 ++++---- src/librustc/diagnostics.rs | 2 - src/librustc/middle/traits/select.rs | 7 ++- src/librustc/middle/traits/util.rs | 2 +- src/librustc/middle/ty.rs | 2 +- .../trans/debuginfo/metadata.rs | 8 ++- src/librustc_trans/trans/expr.rs | 4 +- src/librustc_typeck/check/cast.rs | 55 ++++++++++--------- src/librustc_typeck/check/coercion.rs | 10 +++- src/librustc_typeck/check/regionck.rs | 1 + src/librustc_typeck/coherence/mod.rs | 41 +++++--------- src/librustc_typeck/coherence/orphan.rs | 2 +- src/librustc_typeck/diagnostics.rs | 6 +- src/libstd/sync/mutex.rs | 23 ++++---- src/libstd/sync/rwlock.rs | 23 ++++---- src/test/compile-fail/fat-ptr-cast.rs | 4 +- 19 files changed, 118 insertions(+), 109 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 837cf590024..15d6e6fa960 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -460,7 +460,6 @@ impl Deref for Rc { } #[cfg(stage0)] // SNAP c64d671 -#[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Rc { /// Drops the `Rc`. @@ -512,7 +511,6 @@ impl Drop for Rc { } #[cfg(not(stage0))] // SNAP c64d671 -#[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Rc { /// Drops the `Rc`. @@ -933,7 +931,6 @@ impl Weak { } #[cfg(stage0)] // SNAP c64d671 -#[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Weak { /// Drops the `Weak`. @@ -979,7 +976,6 @@ impl Drop for Weak { } #[cfg(not(stage0))] // SNAP c64d671 -#[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Weak { /// Drops the `Weak`. diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index bf5fdb973eb..45a80122104 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -707,5 +707,4 @@ impl UnsafeCell { #![allow(trivial_casts)] &self.value as *const T as *mut T } - } diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 1a2473fda41..9396adc0fe5 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -1220,24 +1220,33 @@ pub trait CoerceUnsized { // Empty. } +// &mut T -> &mut U #[cfg(not(stage0))] // SNAP c64d671 impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {} +// &mut T -> &U #[cfg(not(stage0))] // SNAP c64d671 impl<'a, 'b: 'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {} +// &mut T -> *mut U #[cfg(not(stage0))] // SNAP c64d671 impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {} +// &mut T -> *const U #[cfg(not(stage0))] // SNAP c64d671 impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {} +// &T -> &U #[cfg(not(stage0))] // SNAP c64d671 impl<'a, 'b: 'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} +// &T -> *const U #[cfg(not(stage0))] // SNAP c64d671 impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a T {} +// *mut T -> *mut U #[cfg(not(stage0))] // SNAP c64d671 impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} +// *mut T -> *const U #[cfg(not(stage0))] // SNAP c64d671 impl, U: ?Sized> CoerceUnsized<*const U> for *mut T {} +// *const T -> *const U #[cfg(not(stage0))] // SNAP c64d671 impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} diff --git a/src/libcoretest/cell.rs b/src/libcoretest/cell.rs index 0bd0b66318f..f02312b8641 100644 --- a/src/libcoretest/cell.rs +++ b/src/libcoretest/cell.rs @@ -172,14 +172,15 @@ fn unsafe_cell_unsized() { assert_eq!(unsafe { &mut *cell.get() }, comp); } -#[test] -fn refcell_unsized() { - let cell: &RefCell<[i32]> = &RefCell::new([1, 2, 3]); - { - let b = &mut *cell.borrow_mut(); - b[0] = 4; - b[2] = 5; - } - let comp: &mut [i32] = &mut [4, 2, 5]; - assert_eq!(&*cell.borrow(), comp); -} +// FIXME(#25351) needs deeply nested coercions of DST structs. +// #[test] +// fn refcell_unsized() { +// let cell: &RefCell<[i32]> = &RefCell::new([1, 2, 3]); +// { +// let b = &mut *cell.borrow_mut(); +// b[0] = 4; +// b[2] = 5; +// } +// let comp: &mut [i32] = &mut [4, 2, 5]; +// assert_eq!(&*cell.borrow(), comp); +// } diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index c8788f76081..bb50d5110cb 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -808,8 +808,6 @@ register_diagnostics! { E0019, E0022, E0038, - E0079, // enum variant: expected signed integer constant - E0080, // enum variant: constant evaluation error E0109, E0110, E0134, diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 2541bba5d9a..a4ed73d7358 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1369,7 +1369,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn assemble_candidates_for_unsizing(&mut self, obligation: &TraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>) { - // TODO is it Ok to skip the binder here? + // It is ok to skip past the higher-ranked binders here because the `match` + // below does not consider regions at all. let source = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); let target = self.infcx.shallow_resolve(obligation.predicate.0.input_types()[0]); @@ -1494,7 +1495,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &ClosureCandidate(..) | &FnPointerCandidate(..) | &BuiltinObjectCandidate(..) | - &&BuiltinUnsizeCandidate(..) | + &BuiltinUnsizeCandidate(..) | &DefaultImplObjectCandidate(..) | &BuiltinCandidate(..) => { // We have a where-clause so don't go around looking @@ -2498,7 +2499,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::lookup_field_type_unsubstituted(tcx, def_id, f.id) }).collect::>(); - // The last field of the structure has to exist and be a + // FIXME(#25351) The last field of the structure has to exist and be a // type parameter (for now, to avoid tracking edge cases). let i = if let Some(&ty::ty_param(p)) = fields.last().map(|ty| &ty.sty) { assert!(p.space == TypeSpace); diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index ea4bc029ed6..f30f8560b9f 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -377,7 +377,7 @@ pub fn predicate_for_trait_def<'tcx>( let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs(Substs::new_trait(ty_params, vec![], param_ty)) - }); + }; predicate_for_trait_ref(cause, trait_ref, recursion_depth) } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 5a84edd3cdf..9054cd65473 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4420,7 +4420,7 @@ pub fn deref<'tcx>(ty: Ty<'tcx>, explicit: bool) -> Option> { pub fn type_content<'tcx>(ty: Ty<'tcx>) -> Ty<'tcx> { match ty.sty { ty_uniq(ty) => ty, - ty_rptr(_, mt) |ty_ptr(mt) => mt.ty, + ty_rptr(_, mt) | ty_ptr(mt) => mt.ty, _ => ty } } diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index bd04bd7a754..ab86cd7cdde 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -1058,6 +1058,7 @@ impl MetadataCreationResult { } } +#[derive(Debug)] enum MemberOffset { FixedMemberOffset { bytes: usize }, // For ComputedMemberOffset, the offset is read from the llvm type definition. @@ -1066,6 +1067,7 @@ enum MemberOffset { // Description of a type member, which can either be a regular field (as in // structs or tuples) or an enum variant. +#[derive(Debug)] struct MemberDescription { name: String, llvm_type: Type, @@ -1163,13 +1165,13 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, span: Span) -> RecursiveTypeDescription<'tcx> { let struct_name = compute_debuginfo_type_name(cx, struct_type, false); - let struct_llvm_type = type_of::type_of(cx, struct_type); + let struct_llvm_type = type_of::in_memory_type_of(cx, struct_type); let (containing_scope, _) = get_namespace_and_span_for_item(cx, def_id); let struct_metadata_stub = create_struct_stub(cx, struct_llvm_type, - &struct_name[..], + &struct_name, unique_type_id, containing_scope); @@ -1299,7 +1301,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { set_members_of_composite_type(cx, variant_type_metadata, variant_llvm_type, - &member_descriptions[..]); + &member_descriptions); MemberDescription { name: "".to_string(), llvm_type: variant_llvm_type, diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 4018df0da47..270aacfe143 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -487,11 +487,11 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let trait_substs = Substs::erased(VecPerParamSpace::new(vec![target.ty], vec![source.ty], Vec::new())); - let trait_ref = ty::Binder(Rc::new(ty::TraitRef { + let trait_ref = ty::Binder(ty::TraitRef { def_id: langcall(bcx, Some(span), "coercion", CoerceUnsizedTraitLangItem), substs: bcx.tcx().mk_substs(trait_substs) - })); + }); let kind = match fulfill_obligation(bcx.ccx(), span, trait_ref) { traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index bfd159720c2..bc6159c0cff 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -60,28 +60,29 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { let e = &cast.expr; let t_e = structurally_resolved_type(fcx, span, cast.expr_ty); let t_1 = structurally_resolved_type(fcx, span, cast.cast_ty); + let tcx = fcx.tcx(); // Check for trivial casts. if !ty::type_has_ty_infer(t_1) { if let Ok(()) = coercion::mk_assignty(fcx, e, t_e, t_1) { if ty::type_is_numeric(t_1) && ty::type_is_numeric(t_e) { - fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS, - e.id, - span, - format!("trivial numeric cast: `{}` as `{}`. Cast can be \ - replaced by coercion, this might require type \ - ascription or a temporary variable", - fcx.infcx().ty_to_string(t_e), - fcx.infcx().ty_to_string(t_1))); + tcx.sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS, + e.id, + span, + format!("trivial numeric cast: `{}` as `{}`. Cast can be \ + replaced by coercion, this might require type \ + ascription or a temporary variable", + fcx.infcx().ty_to_string(t_e), + fcx.infcx().ty_to_string(t_1))); } else { - fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_CASTS, - e.id, - span, - format!("trivial cast: `{}` as `{}`. Cast can be \ - replaced by coercion, this might require type \ - ascription or a temporary variable", - fcx.infcx().ty_to_string(t_e), - fcx.infcx().ty_to_string(t_1))); + tcx.sess.add_lint(lint::builtin::TRIVIAL_CASTS, + e.id, + span, + format!("trivial cast: `{}` as `{}`. Cast can be \ + replaced by coercion, this might require type \ + ascription or a temporary variable", + fcx.infcx().ty_to_string(t_e), + fcx.infcx().ty_to_string(t_1))); } return; } @@ -91,14 +92,14 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { let t_e_is_scalar = ty::type_is_scalar(t_e); let t_e_is_integral = ty::type_is_integral(t_e); let t_e_is_float = ty::type_is_floating_point(t_e); - let t_e_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_e); + let t_e_is_c_enum = ty::type_is_c_like_enum(tcx, t_e); let t_1_is_scalar = ty::type_is_scalar(t_1); let t_1_is_integral = ty::type_is_integral(t_1); let t_1_is_char = ty::type_is_char(t_1); let t_1_is_bare_fn = ty::type_is_bare_fn(t_1); let t_1_is_float = ty::type_is_floating_point(t_1); - let t_1_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_1); + let t_1_is_c_enum = ty::type_is_c_like_enum(tcx, t_1); let t1_is_fat_ptr = fcx.type_is_fat_ptr(t_1, span); // casts to scalars other than `char` and `bare fn` are trivial @@ -114,7 +115,7 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { }, t_e, None); } } else if t_1.sty == ty::ty_bool { - span_err!(fcx.tcx().sess, span, E0054, + span_err!(tcx.sess, span, E0054, "cannot cast as `bool`, compare with zero instead"); } else if t_e_is_float && (t_1_is_scalar || t_1_is_c_enum) && !(t_1_is_integral || t_1_is_float) { @@ -174,12 +175,16 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { } else if t1_is_fat_ptr { // FIXME This should be allowed where the lefthandside is also a fat // pointer and is the same kind of fat pointer, i.e., array to array, - // trait object to trait object. - fcx.type_error_message(span, |actual| { - format!("cast to fat pointer: `{}` as `{}`", - actual, - fcx.infcx().ty_to_string(t_1)) - }, t_e, None); + // trait object to trait object. That is a bit looser than the current + // rquirement that they are pointers to the same type. + if !(fcx.type_is_fat_ptr(t_e, span) && + ty::deref(t_1, true).unwrap().ty == ty::deref(t_e, true).unwrap().ty) { + fcx.type_error_message(span, |actual| { + format!("cast to fat pointer: `{}` as `{}`", + actual, + fcx.infcx().ty_to_string(t_1)) + }, t_e, None); + } } else if !(t_e_is_scalar && t_1_is_trivial) { fcx.type_error_message(span, |actual| { format!("non-scalar cast: `{}` as `{}`", diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index d33553f3859..dd63a512ae3 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -285,14 +285,19 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Create an obligation for `Source: CoerceUnsized`. let cause = ObligationCause::misc(self.origin.span(), self.fcx.body_id); - queue.push_back(predicate_for_trait_def(self.tcx(), cause, coerce_unsized_did, - 0, source, vec![target])); + queue.push_back(predicate_for_trait_def(self.tcx(), + cause, + coerce_unsized_did, + 0, + source, + vec![target])); // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where // inference might unify those two inner type variables later. let traits = [coerce_unsized_did, unsize_did]; while let Some(obligation) = queue.pop_front() { + debug!("coerce_unsized resolve step: {}", obligation.repr(self.tcx())); let trait_ref = match obligation.predicate { ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => { tr.clone() @@ -305,6 +310,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { match selcx.select(&obligation.with(trait_ref)) { // Uncertain or unimplemented. Ok(None) | Err(traits::Unimplemented) => { + debug!("coerce_unsized: early return - can't prove obligation"); return Err(ty::terr_mismatch); } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 337088c313d..090d111b62b 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -85,6 +85,7 @@ use astconv::AstConv; use check::dropck; use check::FnCtxt; +use middle::free_region::FreeRegionMap; use middle::implicator; use middle::mem_categorization as mc; use middle::region::CodeExtent; diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index c6e0bb676f7..58ad8ce8628 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -29,6 +29,7 @@ use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int}; use middle::ty::{ty_uint, ty_closure, ty_uniq, ty_bare_fn}; use middle::ty::ty_projection; use middle::ty; +use middle::free_region::FreeRegionMap; use CrateCtxt; use middle::infer::{self, InferCtxt, new_infer_ctxt}; use std::cell::RefCell; @@ -439,32 +440,19 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } }; - let trait_impls = match tcx.trait_impls - .borrow() - .get(&coerce_unsized_trait) - .cloned() { - None => { - debug!("check_implementations_of_coerce_unsized(): no types \ - with implementations of `CoerceUnsized` found"); - return - } - Some(found_impls) => found_impls - }; + let trait_def = ty::lookup_trait_def(tcx, coerce_unsized_trait); - // Clone first to avoid a double borrow error. - let trait_impls = trait_impls.borrow().clone(); - - for &impl_did in &trait_impls { + trait_def.for_each_impl(tcx, |impl_did| { debug!("check_implementations_of_coerce_unsized: impl_did={}", impl_did.repr(tcx)); if impl_did.krate != ast::LOCAL_CRATE { debug!("check_implementations_of_coerce_unsized(): impl not \ in this crate"); - continue + return; } - let source = self.get_self_type_for_implementation(impl_did).ty; + let source = ty::lookup_item_type(tcx, impl_did).ty; let trait_ref = ty::impl_id_to_trait_ref(self.crate_context.tcx, impl_did.node); let target = *trait_ref.substs.types.get(subst::TypeSpace, 0); @@ -507,12 +495,12 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { if def_id_a != def_id_b { let source_path = ty::item_path_str(tcx, def_id_a); let target_path = ty::item_path_str(tcx, def_id_b); - span_err!(tcx.sess, span, E0373, + span_err!(tcx.sess, span, E0377, "the trait `CoerceUnsized` may only be implemented \ for a coercion between structures with the same \ definition; expected {}, found {}", source_path, target_path); - continue; + return; } let origin = infer::Misc(span); @@ -532,7 +520,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { "the trait `CoerceUnsized` may only be implemented \ for a coercion between structures with one field \ being coerced, none found"); - continue; + return; } else if diff_fields.len() > 1 { span_err!(tcx.sess, span, E0375, "the trait `CoerceUnsized` may only be implemented \ @@ -549,7 +537,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { a.repr(tcx), b.repr(tcx)) }).collect::>().connect(", ")); - continue; + return; } let (i, a, b) = diff_fields[0]; @@ -561,7 +549,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { span_err!(tcx.sess, span, E0376, "the trait `CoerceUnsized` may only be implemented \ for a coercion between structures"); - continue; + return; } }; @@ -578,14 +566,15 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { traits::report_fulfillment_errors(&infcx, &errors); } - // Finally, resolve all regions. This catches wily misuses of lifetime - // parameters. - infcx.resolve_regions_and_report_errors(impl_did.node); + // Finally, resolve all regions. + let mut free_regions = FreeRegionMap::new(); + free_regions.relate_free_regions_from_predicates(tcx, ¶m_env.caller_bounds); + infcx.resolve_regions_and_report_errors(&free_regions, impl_did.node); if let Some(kind) = kind { tcx.custom_coerce_unsized_kinds.borrow_mut().insert(impl_did, kind); } - } + }); } } diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index c75a0d816a8..4c9fe6492e9 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -323,7 +323,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { return; } if Some(trait_def_id) == self.tcx.lang_items.unsize_trait() { - span_err!(self.tcx.sess, item.span, E0323, + span_err!(self.tcx.sess, item.span, E0328, "explicit impls for the `Unsize` trait are not permitted"); return; } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index ac10a4e7121..e92779641c9 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -452,13 +452,13 @@ register_diagnostics! { E0369, // binary operation `` cannot be applied to types E0371, // impl Trait for Trait is illegal E0372, // impl Trait for Trait where Trait is not object safe - E0373, // the trait `CoerceUnsized` may only be implemented for a coercion - // between structures with the same definition E0374, // the trait `CoerceUnsized` may only be implemented for a coercion // between structures with one field being coerced, none found E0375, // the trait `CoerceUnsized` may only be implemented for a coercion // between structures with one field being coerced, but multiple // fields need coercions - E0376 // the trait `CoerceUnsized` may only be implemented for a coercion + E0376, // the trait `CoerceUnsized` may only be implemented for a coercion // between structures + E0377 // the trait `CoerceUnsized` may only be implemented for a coercion + // between structures with the same definition } diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index febf5f1b183..f9ed7c863d1 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -531,15 +531,16 @@ mod tests { assert_eq!(*lock, 2); } - #[test] - fn test_mutex_unsized() { - let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]); - { - let b = &mut *mutex.lock().unwrap(); - b[0] = 4; - b[2] = 5; - } - let comp: &[i32] = &[4, 2, 5]; - assert_eq!(&*mutex.lock().unwrap(), comp); - } + // FIXME(#25351) needs deeply nested coercions of DST structs. + // #[test] + // fn test_mutex_unsized() { + // let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]); + // { + // let b = &mut *mutex.lock().unwrap(); + // b[0] = 4; + // b[2] = 5; + // } + // let comp: &[i32] = &[4, 2, 5]; + // assert_eq!(&*mutex.lock().unwrap(), comp); + // } } diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 625377df7d6..36f6fbf3b72 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -573,17 +573,18 @@ mod tests { assert_eq!(*lock, 2); } - #[test] - fn test_rwlock_unsized() { - let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]); - { - let b = &mut *rw.write().unwrap(); - b[0] = 4; - b[2] = 5; - } - let comp: &[i32] = &[4, 2, 5]; - assert_eq!(&*rw.read().unwrap(), comp); - } + // FIXME(#25351) needs deeply nested coercions of DST structs. + // #[test] + // fn test_rwlock_unsized() { + // let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]); + // { + // let b = &mut *rw.write().unwrap(); + // b[0] = 4; + // b[2] = 5; + // } + // let comp: &[i32] = &[4, 2, 5]; + // assert_eq!(&*rw.read().unwrap(), comp); + // } #[test] fn test_rwlock_try_write() { diff --git a/src/test/compile-fail/fat-ptr-cast.rs b/src/test/compile-fail/fat-ptr-cast.rs index 415785a1174..2099424b05c 100644 --- a/src/test/compile-fail/fat-ptr-cast.rs +++ b/src/test/compile-fail/fat-ptr-cast.rs @@ -16,8 +16,8 @@ fn main() { let a: &[i32] = &[1, 2, 3]; let b: Box<[i32]> = Box::new([1, 2, 3]); - a as usize; //~ ERROR illegal cast - b as usize; //~ ERROR illegal cast + a as usize; //~ ERROR non-scalar cast + b as usize; //~ ERROR non-scalar cast let a: usize = 42; a as *const [i32]; //~ ERROR cast to fat pointer: `usize` as `*const [i32]` From 31bb4ab759e4fa7c57f5d72ceb6b0189edf8a749 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 13 May 2015 14:57:47 +1200 Subject: [PATCH 6/7] Fix binder skipping --- src/librustc/middle/traits/select.rs | 31 +++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index a4ed73d7358..cb889b76eac 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1369,9 +1369,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn assemble_candidates_for_unsizing(&mut self, obligation: &TraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>) { - // It is ok to skip past the higher-ranked binders here because the `match` - // below does not consider regions at all. - let source = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); + // We currently never consider higher-ranked obligations e.g. + // `for<'a> &'a T: Unsize` to be implemented. This is not + // because they are a priori invalid, and we could potentially add support + // for them later, it's just that there isn't really a strong need for it. + // A `T: Unsize` obligation is always used as part of a `T: CoerceUnsize` + // impl, and those are generally applied to concrete types. + // + // That said, one might try to write a fn with a where clause like + // for<'a> Foo<'a, T>: Unsize> + // where the `'a` is kind of orthogonal to the relevant part of the `Unsize`. + // Still, you'd be more likely to write that where clause as + // T: Trait + // so it seems ok if we (conservatively) fail to accept that `Unsize` + // obligation above. Should be possible to extend this in the future. + let self_ty = match ty::no_late_bound_regions(self.tcx(), &obligation.self_ty()) { + Some(t) => t, + None => { + // Don't add any candidates if there are bound regions. + return; + } + }; + let source = self.infcx.shallow_resolve(self_ty); let target = self.infcx.shallow_resolve(obligation.predicate.0.input_types()[0]); debug!("assemble_candidates_for_unsizing(source={}, target={})", @@ -2403,8 +2422,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { SelectionError<'tcx>> { let tcx = self.tcx(); - // TODO is this skip_binder Ok? - let source = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); + // assemble_candidates_for_unsizing should ensure there are no late bound + // regions here. See the comment there for more details. + let source = self.infcx.shallow_resolve( + ty::no_late_bound_regions(tcx, &obligation.self_ty()).unwrap()); let target = self.infcx.shallow_resolve(obligation.predicate.0.input_types()[0]); debug!("confirm_builtin_unsize_candidate(source={}, target={})", From b799cd83cc797b580be2d1492e6ae014848636ee Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 13 May 2015 15:05:02 +1200 Subject: [PATCH 7/7] Remove SNAP comments --- src/liballoc/boxed.rs | 6 +++--- src/liballoc/rc.rs | 10 +++++----- src/libcore/marker.rs | 2 +- src/libcore/mem.rs | 8 ++++---- src/libcore/nonzero.rs | 4 ++-- src/libcore/ops.rs | 22 +++++++++++----------- src/librustc_typeck/diagnostics.rs | 1 - 7 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 757c799d85c..35732dacd44 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -62,9 +62,9 @@ use core::ops::{Deref, DerefMut}; use core::ptr::{Unique}; use core::raw::{TraitObject}; -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] use core::marker::Unsize; -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] use core::ops::CoerceUnsized; /// A value that represents the heap. This is the default place that the `box` @@ -396,5 +396,5 @@ impl<'a,A,R> FnOnce for Box+Send+'a> { } } -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl, U: ?Sized> CoerceUnsized> for Box {} diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 15d6e6fa960..f2b83fdeefa 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -228,7 +228,7 @@ impl !marker::Sync for Rc {} #[cfg(not(stage0))] impl !marker::Sync for Rc {} -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl, U: ?Sized> CoerceUnsized> for Rc {} impl Rc { @@ -459,7 +459,7 @@ impl Deref for Rc { } } -#[cfg(stage0)] // SNAP c64d671 +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Rc { /// Drops the `Rc`. @@ -510,7 +510,7 @@ impl Drop for Rc { } } -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Rc { /// Drops the `Rc`. @@ -930,7 +930,7 @@ impl Weak { } } -#[cfg(stage0)] // SNAP c64d671 +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Weak { /// Drops the `Weak`. @@ -975,7 +975,7 @@ impl Drop for Weak { } } -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Weak { /// Drops the `Weak`. diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 968f68a78a7..5909c5cc30e 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -55,7 +55,7 @@ pub trait Sized { /// Types that can be "unsized" to a dynamically sized type. #[unstable(feature = "core")] -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] #[lang="unsize"] pub trait Unsize { // Empty. diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index bb94cd886d7..173b73fdb09 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -95,7 +95,7 @@ pub fn size_of() -> usize { /// /// assert_eq!(4, mem::size_of_val(&5i32)); /// ``` -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn size_of_val(val: &T) -> usize { @@ -111,7 +111,7 @@ pub fn size_of_val(val: &T) -> usize { /// /// assert_eq!(4, mem::size_of_val(&5i32)); /// ``` -#[cfg(stage0)] // SNAP c64d671 +#[cfg(stage0)] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn size_of_val(_val: &T) -> usize { @@ -144,7 +144,7 @@ pub fn min_align_of() -> usize { /// /// assert_eq!(4, mem::min_align_of_val(&5i32)); /// ``` -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn min_align_of_val(val: &T) -> usize { @@ -160,7 +160,7 @@ pub fn min_align_of_val(val: &T) -> usize { /// /// assert_eq!(4, mem::min_align_of_val(&5i32)); /// ``` -#[cfg(stage0)] // SNAP c64d671 +#[cfg(stage0)] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn min_align_of_val(_val: &T) -> usize { diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 85957382826..59819fd500d 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -12,7 +12,7 @@ use marker::Sized; use ops::Deref; -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] use ops::CoerceUnsized; /// Unsafe trait to indicate what types are usable with the NonZero struct @@ -57,5 +57,5 @@ impl Deref for NonZero { } } -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl, U: Zeroable> CoerceUnsized> for NonZero {} diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 9396adc0fe5..f16614cfd09 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -70,7 +70,7 @@ use marker::Sized; use fmt; -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] use marker::Unsize; /// The `Drop` trait is used to run some code when a value goes out of scope. This @@ -1214,39 +1214,39 @@ mod impls { /// Trait that indicates that this is a pointer or a wrapper for one, /// where unsizing can be performed on the pointee. #[unstable(feature = "core")] -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] #[lang="coerce_unsized"] pub trait CoerceUnsized { // Empty. } // &mut T -> &mut U -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {} // &mut T -> &U -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl<'a, 'b: 'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {} // &mut T -> *mut U -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {} // &mut T -> *const U -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {} // &T -> &U -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl<'a, 'b: 'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} // &T -> *const U -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a T {} // *mut T -> *mut U -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} // *mut T -> *const U -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl, U: ?Sized> CoerceUnsized<*const U> for *mut T {} // *const T -> *const U -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index e92779641c9..8375061aa09 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -309,7 +309,6 @@ register_diagnostics! { E0034, // multiple applicable methods in scope E0035, // does not take type parameters E0036, // incorrect number of type parameters given for this method - E0038, // cannot convert to a trait object because trait is not object-safe E0040, // explicit use of destructor method E0044, // foreign items may not have type parameters E0045, // variadic function must have C calling convention