From a18bd5a512f541ac2d9b169b210dac419ad10af0 Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Sun, 3 Sep 2017 23:48:02 +0100 Subject: [PATCH 01/17] Add a DynSized trait. The DynSized trait is implemented by all types which have a size and alignment known at runtime. This includes every type other than extern types, introduced in RFC 1861 and implemented in #44295, which are completely opaque. The main motivation for this trait is to prevent the use of !DynSized types as struct tails. Consider for example the following types : ```rust extern { type foo; } struct A { a_x: u8 a_y: T } struct B { b_x: u8 b_y: T } ``` Before this change, the type `A>` is considered well-formed. However, the alignment of `B` and thus the offset of the `a_y` field depends on the alignment of `foo`, which is unknown. By introducing this new trait, struct tails are now required to implement `DynSized`, such that their alignment is known. The trait is an implicit bound, making `A>` ill-formed. Just like the `Sized` trait, the default bound can be opted-out by using `?DynSized`. --- src/libcore/marker.rs | 97 +++++++++++++++++------ src/libcore/ptr.rs | 2 +- src/librustc/dep_graph/dep_node.rs | 2 + src/librustc/middle/lang_items.rs | 1 + src/librustc/traits/error_reporting.rs | 3 + src/librustc/traits/mod.rs | 3 + src/librustc/traits/select.rs | 56 +++++++++++++ src/librustc/traits/structural_impls.rs | 3 + src/librustc/ty/maps/config.rs | 6 ++ src/librustc/ty/maps/mod.rs | 6 ++ src/librustc/ty/mod.rs | 97 +++++++++++++++++++++++ src/librustc/ty/util.rs | 25 +++++- src/librustc/ty/wf.rs | 14 +++- src/librustc/util/ppaux.rs | 12 ++- src/librustc_passes/ast_validation.rs | 34 +++----- src/librustc_trans/common.rs | 4 + src/librustc_trans/context.rs | 4 + src/librustc_trans/intrinsic.rs | 32 +++++--- src/librustc_trans/mir/lvalue.rs | 16 ++-- src/librustc_typeck/astconv.rs | 11 +++ src/librustc_typeck/check/wfcheck.rs | 11 +++ src/librustc_typeck/coherence/mod.rs | 10 ++- src/librustc_typeck/collect.rs | 101 ++++++++++++++++-------- src/libstd/lib.rs | 1 + src/libstd/panic.rs | 31 +++++++- 25 files changed, 470 insertions(+), 112 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 0a8127f4ce4fe..07184fabdbc6b 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -40,6 +40,16 @@ use hash::Hasher; /// [ub]: ../../reference/behavior-considered-undefined.html #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(stage0, lang = "send")] +#[cfg(not(stage0))] +#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"] +pub unsafe trait Send: ?DynSized { + // empty. +} + +/// docs +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(stage0, lang = "send")] +#[cfg(stage0)] #[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"] pub unsafe trait Send { // empty. @@ -51,9 +61,9 @@ pub unsafe trait Send { unsafe impl Send for .. { } #[stable(feature = "rust1", since = "1.0.0")] -impl !Send for *const T { } +impl !Send for *const T { } #[stable(feature = "rust1", since = "1.0.0")] -impl !Send for *mut T { } +impl !Send for *mut T { } /// Types with a constant size known at compile time. /// @@ -96,6 +106,29 @@ pub trait Sized { // Empty. } +/// Types with a size known at run time. +/// +/// This trait is implemented both by `Sized` types, and by dynamically sized +/// types such as slices and [trait objects]. [Extern types], whose size is not +/// known, even at runtime, do not implement this trait. +/// +/// All traits and type parameters have an implicit bound of `DynSized`. The +/// special syntax `?DynSized` can be used to remove this bound if it's not +/// appropriate. +/// +/// [trait object]: ../../book/first-edition/trait-objects.html +#[cfg(not(stage0))] +#[unstable(feature = "dynsized", issue = "0")] +#[lang = "dynsized"] +#[rustc_on_unimplemented = "`{Self}` does not have a size known at run-time"] +#[fundamental] +pub trait DynSized: ?DynSized { + // Empty. +} + +#[cfg(stage0)] +use self::Sized as DynSized; // This is just so we don't have to stage too much stuff + /// Types that can be "unsized" to a dynamically-sized type. /// /// For example, the sized array type `[i8; 2]` implements `Unsize<[i8]>` and @@ -345,6 +378,16 @@ pub trait Copy : Clone { /// [transmute]: ../../std/mem/fn.transmute.html #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sync"] +#[cfg(not(stage0))] +#[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"] +pub unsafe trait Sync: ?DynSized { + // Empty +} + +/// docs +#[stable(feature = "rust1", since = "1.0.0")] +#[lang = "sync"] +#[cfg(stage0)] #[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"] pub unsafe trait Sync { // Empty @@ -356,56 +399,56 @@ pub unsafe trait Sync { unsafe impl Sync for .. { } #[stable(feature = "rust1", since = "1.0.0")] -impl !Sync for *const T { } +impl !Sync for *const T { } #[stable(feature = "rust1", since = "1.0.0")] -impl !Sync for *mut T { } +impl !Sync for *mut T { } macro_rules! impls{ ($t: ident) => ( #[stable(feature = "rust1", since = "1.0.0")] - impl Hash for $t { + impl Hash for $t { #[inline] fn hash(&self, _: &mut H) { } } #[stable(feature = "rust1", since = "1.0.0")] - impl cmp::PartialEq for $t { + impl cmp::PartialEq for $t { fn eq(&self, _other: &$t) -> bool { true } } #[stable(feature = "rust1", since = "1.0.0")] - impl cmp::Eq for $t { + impl cmp::Eq for $t { } #[stable(feature = "rust1", since = "1.0.0")] - impl cmp::PartialOrd for $t { + impl cmp::PartialOrd for $t { fn partial_cmp(&self, _other: &$t) -> Option { Option::Some(cmp::Ordering::Equal) } } #[stable(feature = "rust1", since = "1.0.0")] - impl cmp::Ord for $t { + impl cmp::Ord for $t { fn cmp(&self, _other: &$t) -> cmp::Ordering { cmp::Ordering::Equal } } #[stable(feature = "rust1", since = "1.0.0")] - impl Copy for $t { } + impl Copy for $t { } #[stable(feature = "rust1", since = "1.0.0")] - impl Clone for $t { + impl Clone for $t { fn clone(&self) -> $t { $t } } #[stable(feature = "rust1", since = "1.0.0")] - impl Default for $t { + impl Default for $t { fn default() -> $t { $t } @@ -548,31 +591,35 @@ macro_rules! impls{ /// [drop check]: ../../nomicon/dropck.html #[lang = "phantom_data"] #[stable(feature = "rust1", since = "1.0.0")] -pub struct PhantomData; +pub struct PhantomData; impls! { PhantomData } -mod impls { - #[stable(feature = "rust1", since = "1.0.0")] - unsafe impl<'a, T: Sync + ?Sized> Send for &'a T {} - #[stable(feature = "rust1", since = "1.0.0")] - unsafe impl<'a, T: Send + ?Sized> Send for &'a mut T {} -} +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<'a, T: Sync + ?DynSized> Send for &'a T {} +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<'a, T: Send + ?DynSized> Send for &'a mut T {} /// Compiler-internal trait used to determine whether a type contains /// any `UnsafeCell` internally, but not through an indirection. /// This affects, for example, whether a `static` of that type is /// placed in read-only static memory or writable static memory. #[lang = "freeze"] +#[cfg(not(stage0))] +unsafe trait Freeze: ?DynSized {} + +/// docs +#[lang = "freeze"] +#[cfg(stage0)] unsafe trait Freeze {} #[allow(unknown_lints)] #[allow(auto_impl)] unsafe impl Freeze for .. {} -impl !Freeze for UnsafeCell {} -unsafe impl Freeze for PhantomData {} -unsafe impl Freeze for *const T {} -unsafe impl Freeze for *mut T {} -unsafe impl<'a, T: ?Sized> Freeze for &'a T {} -unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {} +impl !Freeze for UnsafeCell {} +unsafe impl Freeze for PhantomData {} +unsafe impl Freeze for *const T {} +unsafe impl Freeze for *mut T {} +unsafe impl<'a, T: ?DynSized> Freeze for &'a T {} +unsafe impl<'a, T: ?DynSized> Freeze for &'a mut T {} diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 126558e3025d5..a86db5cc85ae2 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -56,7 +56,7 @@ pub use intrinsics::write_bytes; #[stable(feature = "drop_in_place", since = "1.8.0")] #[lang = "drop_in_place"] #[allow(unconditional_recursion)] -pub unsafe fn drop_in_place(to_drop: *mut T) { +pub unsafe fn drop_in_place(to_drop: *mut T) { // Code here does not matter - this is replaced by the // real drop glue by the compiler. drop_in_place(to_drop); diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 523a244c8361b..d527f16e00955 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -509,6 +509,7 @@ define_dep_nodes!( <'tcx> [] IsForeignItem(DefId), [] TypeParamPredicates { item_id: DefId, param_id: DefId }, [] SizedConstraint(DefId), + [] DynSizedConstraint(DefId), [] DtorckConstraint(DefId), [] AdtDestructor(DefId), [] AssociatedItemDefIds(DefId), @@ -527,6 +528,7 @@ define_dep_nodes!( <'tcx> [] IsCopy { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> }, [] IsSized { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> }, + [] IsDynSized { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> }, [] IsFreeze { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> }, [] NeedsDrop { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> }, [] Layout { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> }, diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 19a43f3b5dd84..b69c41b598eda 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -230,6 +230,7 @@ language_item_table! { F64ImplItem, "f64", f64_impl; SizedTraitLangItem, "sized", sized_trait; + DynSizedTraitLangItem, "dynsized", dynsized_trait; UnsizeTraitLangItem, "unsize", unsize_trait; CopyTraitLangItem, "copy", copy_trait; CloneTraitLangItem, "clone", clone_trait; diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 7c38cf75b8d5a..d5535fc898ac8 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1243,6 +1243,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ObligationCauseCode::StructInitializerSized => { err.note("structs must have a statically known size to be initialized"); } + ObligationCauseCode::FieldDynSized => { + err.note("the last field of a struct or tuple must have a dynamically sized type"); + } ObligationCauseCode::FieldSized(ref item) => { match *item { AdtKind::Struct => { diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 55b1a913f0d1d..c717ed7f26afb 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -137,6 +137,9 @@ pub enum ObligationCauseCode<'tcx> { /// Types of fields (other than the last) in a struct must be sized. FieldSized(AdtKind), + /// Last field of a struct must be DynSized. + FieldDynSized, + /// Constant expressions must be sized. ConstSized, diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 7716770d318ba..771123e196460 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1348,6 +1348,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let sized_conditions = self.sized_conditions(obligation); self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates)?; + } else if lang_items.dynsized_trait() == Some(def_id) { + // DynSized is never implementable by end-users, it is + // always automatically computed. + let dynsized_conditions = self.dynsized_conditions(obligation); + self.assemble_builtin_bound_candidates(dynsized_conditions, + &mut candidates)?; } else if lang_items.unsize_trait() == Some(def_id) { self.assemble_candidates_for_unsizing(obligation, &mut candidates); } else { @@ -2054,6 +2060,53 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } + fn dynsized_conditions(&mut self, obligation: &TraitObligation<'tcx>) + -> BuiltinImplConditions<'tcx> + { + use self::BuiltinImplConditions::{Ambiguous, None, Never, Where}; + + // NOTE: binder moved to (*) + let self_ty = self.infcx.shallow_resolve( + obligation.predicate.skip_binder().self_ty()); + + match self_ty.sty { + ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) | + ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) | + ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyRawPtr(..) | + ty::TyChar | ty::TyRef(..) | ty::TyGenerator(..) | + ty::TyArray(..) | ty::TyClosure(..) | ty::TyNever | + ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) | + ty::TyError => { + // safe for everything + Where(ty::Binder(Vec::new())) + } + + ty::TyTuple(tys, _) => { + Where(ty::Binder(tys.last().into_iter().cloned().collect())) + } + + ty::TyAdt(def, substs) => { + let dynsized_crit = def.dynsized_constraint(self.tcx()); + // (*) binder moved here + Where(ty::Binder( + dynsized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect() + )) + } + + ty::TyForeign(..) => Never, + + ty::TyProjection(_) | ty::TyParam(_) | ty::TyAnon(..) => None, + ty::TyInfer(ty::TyVar(_)) => Ambiguous, + + ty::TyInfer(ty::FreshTy(_)) + | ty::TyInfer(ty::FreshIntTy(_)) + | ty::TyInfer(ty::FreshFloatTy(_)) => { + bug!("asked to assemble builtin bounds of unexpected type: {:?}", + self_ty); + } + } + } + fn copy_clone_conditions(&mut self, obligation: &TraitObligation<'tcx>) -> BuiltinImplConditions<'tcx> { @@ -2382,6 +2435,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { _ if Some(trait_def) == lang_items.sized_trait() => { self.sized_conditions(obligation) } + _ if Some(trait_def) == lang_items.dynsized_trait() => { + self.dynsized_conditions(obligation) + } _ if Some(trait_def) == lang_items.copy_trait() => { self.copy_clone_conditions(obligation) } diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 9231995018065..55a3c00b855bf 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -204,6 +204,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::SizedReturnType => Some(super::SizedReturnType), super::RepeatVec => Some(super::RepeatVec), super::FieldSized(item) => Some(super::FieldSized(item)), + super::FieldDynSized => Some(super::FieldDynSized), super::ConstSized => Some(super::ConstSized), super::SharedStatic => Some(super::SharedStatic), super::BuiltinDerivedObligation(ref cause) => { @@ -522,6 +523,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { super::ReturnNoExpression | super::RepeatVec | super::FieldSized(_) | + super::FieldDynSized | super::ConstSized | super::SharedStatic | super::BlockTailExpression(_) | @@ -570,6 +572,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { super::ReturnNoExpression | super::RepeatVec | super::FieldSized(_) | + super::FieldDynSized | super::ConstSized | super::SharedStatic | super::BlockTailExpression(_) | diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index 066b80cefa4b5..c0f5dad56e028 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -61,6 +61,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::is_sized_raw<'tcx> { } } +impl<'tcx> QueryDescription<'tcx> for queries::is_dynsized_raw<'tcx> { + fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { + format!("computing whether `{}` is `DynSized`", env.value) + } +} + impl<'tcx> QueryDescription<'tcx> for queries::is_freeze_raw<'tcx> { fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { format!("computing whether `{}` is freeze", env.value) diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 2f648e8d3ff82..9cc10ab9ea3ed 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -104,6 +104,7 @@ define_maps! { <'tcx> [] fn adt_def: AdtDefOfItem(DefId) -> &'tcx ty::AdtDef, [] fn adt_destructor: AdtDestructor(DefId) -> Option, [] fn adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>], + [] fn adt_dynsized_constraint: DynSizedConstraint(DefId) -> &'tcx [Ty<'tcx>], [] fn adt_dtorck_constraint: DtorckConstraint(DefId) -> ty::DtorckConstraint<'tcx>, /// True if this is a const fn @@ -261,6 +262,7 @@ define_maps! { <'tcx> // `ty.is_copy()`, etc, since that will prune the environment where possible. [] fn is_copy_raw: is_copy_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, [] fn is_sized_raw: is_sized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, + [] fn is_dynsized_raw: is_dynsized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, [] fn is_freeze_raw: is_freeze_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, [] fn needs_drop_raw: needs_drop_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, [] fn layout_raw: layout_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) @@ -438,6 +440,10 @@ fn is_freeze_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepCo DepConstructor::IsFreeze { param_env } } +fn is_dynsized_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { + DepConstructor::IsDynSized { param_env } +} + fn needs_drop_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { DepConstructor::NeedsDrop { param_env } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 48ec92a255b4c..041daff7c0cf8 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1818,6 +1818,18 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } + /// Same as `sized_constraint`, but for DynSized + pub fn dynsized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx [Ty<'tcx>] { + match queries::adt_dynsized_constraint::try_get(tcx, DUMMY_SP, self.did) { + Ok(tys) => tys, + Err(mut bug) => { + debug!("adt_dynsized_constraint: {:?} is recursive", self); + bug.delay_as_bug(); + tcx.intern_type_list(&[tcx.types.err]) + } + } + } + fn sized_constraint_for_ty(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) @@ -1887,6 +1899,74 @@ impl<'a, 'gcx, 'tcx> AdtDef { debug!("sized_constraint_for_ty({:?}) = {:?}", ty, result); result } + + fn dynsized_constraint_for_ty(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + ty: Ty<'tcx>) + -> Vec> { + let result = match ty.sty { + TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | + TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | + TyStr | TyDynamic(..) | TySlice(_) | TyArray(..) | + TyTuple(..) | TyAdt(..) | TyClosure(..) | TyGenerator(..) | + TyNever => { + vec![] + } + + TyForeign(..) | TyError => { + // these are never DynSized - return the target type + vec![ty] + } + + TyProjection(..) | TyAnon(..) => { + // must calculate explicitly. + // FIXME: consider special-casing always-DynSized projections + vec![ty] + } + + TyParam(..) => { + // perf hack: if there is a `T: Sized` or `T: DynSized` bound, then + // we know that `T` is DynSized and do not need to check + // it on the impl. + + let sized_trait = match tcx.lang_items().sized_trait() { + Some(x) => x, + _ => return vec![ty] + }; + + let dynsized_trait = match tcx.lang_items().dynsized_trait() { + Some(x) => x, + _ => return vec![ty] + }; + + let sized_predicate = Binder(TraitRef { + def_id: sized_trait, + substs: tcx.mk_substs_trait(ty, &[]) + }).to_predicate(); + + let dynsized_predicate = Binder(TraitRef { + def_id: dynsized_trait, + substs: tcx.mk_substs_trait(ty, &[]) + }).to_predicate(); + + let predicates = tcx.predicates_of(self.did).predicates; + if predicates.into_iter().any(|p| { + p == sized_predicate || p == dynsized_predicate + }) { + vec![] + } else { + vec![ty] + } + } + + TyInfer(..) => { + bug!("unexpected type `{:?}` in dynsized_constraint_for_ty", + ty) + } + }; + debug!("dynsized_constraint_for_ty({:?}) = {:?}", ty, result); + result + } } impl<'a, 'gcx, 'tcx> VariantDef { @@ -2501,6 +2581,22 @@ fn adt_sized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, result } +fn adt_dynsized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> &'tcx [Ty<'tcx>] { + let def = tcx.adt_def(def_id); + + let result = tcx.intern_type_list(&def.variants.iter().flat_map(|v| { + v.fields.last() + }).flat_map(|f| { + def.dynsized_constraint_for_ty(tcx, tcx.type_of(f.did)) + }).collect::>()); + + debug!("adt_dynsized_constraint: {:?} => {:?}", def, result); + + result +} + /// Calculates the dtorck constraint for a type. fn adt_dtorck_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) @@ -2625,6 +2721,7 @@ pub fn provide(providers: &mut ty::maps::Providers) { associated_item, associated_item_def_ids, adt_sized_constraint, + adt_dynsized_constraint, adt_dtorck_constraint, def_span, param_env, diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 23dd3f1bc2bba..ebac6d6a2b140 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -824,11 +824,19 @@ impl<'a, 'tcx> ty::TyS<'tcx> { pub fn is_sized(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, - span: Span)-> bool + span: Span) -> bool { tcx.at(span).is_sized_raw(param_env.and(self)) } + pub fn is_dynsized(&'tcx self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + span: Span) -> bool + { + tcx.at(span).is_dynsized_raw(param_env.and(self)) + } + pub fn is_freeze(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -1065,6 +1073,20 @@ fn is_sized_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, DUMMY_SP)) } +fn is_dynsized_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) + -> bool +{ + let (param_env, ty) = query.into_parts(); + let trait_def_id = tcx.require_lang_item(lang_items::DynSizedTraitLangItem); + tcx.infer_ctxt() + .enter(|infcx| traits::type_known_to_meet_bound(&infcx, + param_env, + ty, + trait_def_id, + DUMMY_SP)) +} + fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool @@ -1215,6 +1237,7 @@ pub fn provide(providers: &mut ty::maps::Providers) { *providers = ty::maps::Providers { is_copy_raw, is_sized_raw, + is_dynsized_raw, is_freeze_raw, needs_drop_raw, ..*providers diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index c631e2c4db51b..9ce0dbdca44d7 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -267,6 +267,17 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { } } + fn require_dynsized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) { + if !subty.has_escaping_regions() { + let cause = self.cause(cause); + let trait_ref = ty::TraitRef { + def_id: self.infcx.tcx.require_lang_item(lang_items::DynSizedTraitLangItem), + substs: self.infcx.tcx.mk_substs_trait(subty, &[]), + }; + self.out.push(traits::Obligation::new(cause, self.param_env, trait_ref.to_predicate())); + } + } + /// Push new obligations into `out`. Returns true if it was able /// to generate all the predicates needed to validate that `ty0` /// is WF. Returns false if `ty0` is an unresolved type variable, @@ -300,10 +311,11 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { } ty::TyTuple(ref tys, _) => { - if let Some((_last, rest)) = tys.split_last() { + if let Some((last, rest)) = tys.split_last() { for elem in rest { self.require_sized(elem, traits::TupleElem); } + self.require_dynsized(last, traits::FieldDynSized); } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index acb929981fbf2..03e0742cff5f6 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -1026,13 +1026,17 @@ define_print! { let mut first = true; let mut is_sized = false; + let mut is_dynsized = false; write!(f, "impl")?; for predicate in bounds.predicates { if let Some(trait_ref) = predicate.to_opt_poly_trait_ref() { - // Don't print +Sized, but rather +?Sized if absent. + // Don't print +Sized/DynSized, but rather +?Sized/?DynSized if absent. if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() { is_sized = true; continue; + } else if Some(trait_ref.def_id()) == tcx.lang_items().dynsized_trait() { + is_dynsized = true; + continue; } print!(f, cx, @@ -1041,7 +1045,11 @@ define_print! { first = false; } } - if !is_sized { + // check for ?DynSized first, so we can output ?DynSized + // instead of ?DynSized + ?Sized + if !is_dynsized { + write!(f, "{}?DynSized", if first { " " } else { "+" })?; + } else if !is_sized { write!(f, "{}?Sized", if first { " " } else { "+" })?; } Ok(()) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 40adc6bcb122f..4085909705ee5 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -91,19 +91,6 @@ impl<'a> AstValidator<'a> { } } - fn no_questions_in_bounds(&self, bounds: &TyParamBounds, where_: &str, is_trait: bool) { - for bound in bounds { - if let TraitTyParamBound(ref poly, TraitBoundModifier::Maybe) = *bound { - let mut err = self.err_handler().struct_span_err(poly.span, - &format!("`?Trait` is not permitted in {}", where_)); - if is_trait { - err.note(&format!("traits are `?{}` by default", poly.trait_ref.path)); - } - err.emit(); - } - } - } - /// matches '-' lit | lit (cf. parser::Parser::parse_pat_literal_maybe_minus), /// or path for ranges. /// @@ -159,16 +146,21 @@ impl<'a> Visitor<'a> for AstValidator<'a> { TyKind::TraitObject(ref bounds, ..) => { let mut any_lifetime_bounds = false; for bound in bounds { - if let RegionTyParamBound(ref lifetime) = *bound { - if any_lifetime_bounds { - span_err!(self.session, lifetime.span, E0226, - "only a single explicit lifetime bound is permitted"); - break; + match *bound { + RegionTyParamBound(ref lifetime) => { + if any_lifetime_bounds { + span_err!(self.session, lifetime.span, E0226, + "only a single explicit lifetime bound is permitted"); + break; + } + any_lifetime_bounds = true; + } + TraitTyParamBound(ref poly, TraitBoundModifier::Maybe) => { + self.session.span_err(poly.span, "`?Trait` is not permitted in trait object types"); } - any_lifetime_bounds = true; + _ => (), } } - self.no_questions_in_bounds(bounds, "trait object types", false); } TyKind::ImplTrait(ref bounds) => { if !bounds.iter() @@ -250,7 +242,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { "auto traits cannot contain items"); } } - self.no_questions_in_bounds(bounds, "supertraits", true); + for trait_item in trait_items { if let TraitItemKind::Method(ref sig, ref block) = trait_item.node { self.check_trait_fn_not_const(sig.constness); diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 7bd8a0c81ee34..3bb7523eef67a 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -49,6 +49,10 @@ pub fn type_is_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> boo ty.is_sized(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) } +pub fn type_is_dynsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { + ty.is_dynsized(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) +} + pub fn type_is_freeze<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { ty.is_freeze(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index b2bb605d01b46..39f0ad66c66f9 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -320,6 +320,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { common::type_is_sized(self.tcx, ty) } + pub fn type_is_dynsized(&self, ty: Ty<'tcx>) -> bool { + common::type_is_dynsized(self.tcx, ty) + } + pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { common::type_is_freeze(self.tcx, ty) } diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index adbb45f893b08..185021e8da5b8 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -144,12 +144,18 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, } "size_of_val" => { let tp_ty = substs.type_at(0); - if let OperandValue::Pair(_, meta) = args[0].val { - let (llsize, _) = - glue::size_and_align_of_dst(bcx, tp_ty, meta); - llsize - } else { + if bcx.ccx.shared().type_is_size(ty_ty) { C_usize(ccx, ccx.size_of(tp_ty).bytes()) + } else if bcx.ccx.shared().type_is_dynsized(tp_ty) { + if let OperandValue::Pair(_, meta) = args[0].val { + let (llsize, _) = + glue::size_and_align_of_dst(bcx, tp_ty, meta); + llsize + } else { + span_bug!(span, "size_of_val: DST pointer layout is not a Pair") + } + } else { + span_bug!(span, "trying to get size of !DynSized type: {:?}", tp_ty) } } "min_align_of" => { @@ -158,12 +164,18 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, } "min_align_of_val" => { let tp_ty = substs.type_at(0); - if let OperandValue::Pair(_, meta) = args[0].val { - let (_, llalign) = - glue::size_and_align_of_dst(bcx, tp_ty, meta); - llalign - } else { + if bcx.ccx.shared().type_is_sized(tp_ty) { C_usize(ccx, ccx.align_of(tp_ty).abi()) + } else if bcx.ccx.shared().type_is_dynsized(tp_ty) { + if let OperandValue::Pair(_, meta) = args[0].val { + let (_, llalign) = + glue::size_and_align_of_dst(bcx, tp_ty, meta); + llalign + } else { + span_bug!(span, "align_of_val: DST pointer layout is not a Pair") + } + } else { + span_bug!(span, "trying to get alignment of !DynSized type: {:?}", tp_ty) } } "pref_align_of" => { diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index 891d52045c217..111794d3ab86f 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -239,18 +239,12 @@ impl<'a, 'tcx> LvalueRef<'tcx> { return simple(); } - // If the type of the last field is [T], str or a foreign type, then we don't need to do - // any adjusments + // If the type of the last field is [T] or str, then we don't need to do + // any adjusments. Otherwise it must be a trait object. match field.ty.sty { - ty::TySlice(..) | ty::TyStr | ty::TyForeign(..) => return simple(), - _ => () - } - - // There's no metadata available, log the case and just do the GEP. - if !self.has_extra() { - debug!("Unsized field `{}`, of `{:?}` has no metadata for adjustment", - ix, Value(self.llval)); - return simple(); + ty::TySlice(..) | ty::TyStr => return simple(), + ty::TyDynamic(..) => (), + _ => bug!("unexpected DST tail: {:?}", fty.sty), } // We need to get the pointer manually now. diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 7aaf65e1fd07d..6cac19a77a39b 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1311,6 +1311,7 @@ fn report_lifetime_number_error(tcx: TyCtxt, span: Span, number: usize, expected pub struct Bounds<'tcx> { pub region_bounds: Vec>, pub implicitly_sized: bool, + pub implicitly_dynsized: bool, pub trait_bounds: Vec>, pub projection_bounds: Vec>, } @@ -1332,6 +1333,16 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> { } } + if self.implicitly_dynsized { + if let Some(dynsized) = tcx.lang_items().dynsized_trait() { + let trait_ref = ty::TraitRef { + def_id: dynsized, + substs: tcx.mk_substs_trait(param_ty, &[]) + }; + vec.push(trait_ref.to_predicate()); + } + } + for ®ion_bound in &self.region_bounds { // account for the binder being introduced below; no need to shift `param_ty` // because, at present at least, it can only refer to early-bound regions diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 37cf67fe53ef6..53d3a267e8b27 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -240,6 +240,17 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { }))); } + // Last field must be DynSized. + if !all_sized && !variant.fields.is_empty() { + let field = &variant.fields[variant.fields.len() - 1]; + fcx.register_bound( + field.ty, + fcx.tcx.require_lang_item(lang_items::DynSizedTraitLangItem), + traits::ObligationCause::new(field.span, + fcx.body_id, + traits::FieldDynSized)); + } + // All field types must be well-formed. for field in &variant.fields { fcx.register_wf_obligation(field.ty, field.span, this.code.clone()) diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 90a0952af0425..60ad745486718 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -53,7 +53,7 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_d let did = Some(trait_def_id); let li = tcx.lang_items(); - // Disallow *all* explicit impls of `Sized` and `Unsize` for now. + // Disallow *all* explicit impls of `Sized`, `DynSized` and `Unsize` for now. if did == li.sized_trait() { let span = tcx.span_of_impl(impl_def_id).unwrap(); struct_span_err!(tcx.sess, @@ -65,6 +65,14 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_d return; } + if did == li.dynsized_trait() { + let span = tcx.span_of_impl(impl_def_id).unwrap(); + tcx.sess.struct_span_err(span, "explicit impls for the `DynSized` trait are not permitted") + .span_label(span, "impl of 'DynSized' not allowed") + .emit(); + return; + } + if did == li.unsize_trait() { let span = tcx.span_of_impl(impl_def_id).unwrap(); span_err!(tcx.sess, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index b5fbbeb1692e6..5dca55ae92b6f 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -27,7 +27,7 @@ use astconv::{AstConv, Bounds}; use lint; use constrained_type_params as ctp; -use middle::lang_items::SizedTraitLangItem; +use middle::lang_items::{DynSizedTraitLangItem, SizedTraitLangItem}; use middle::const_val::ConstVal; use middle::resolve_lifetime as rl; use rustc::traits::Reveal; @@ -1279,10 +1279,35 @@ fn impl_polarity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -// Is it marked with ?Sized -fn is_unsized<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, - ast_bounds: &[hir::TyParamBound], - span: Span) -> bool +// Implicit sizing constraint in bounds. +// This only takes into account defaults and ?Trait bounds, +// not positive bounds such as trait Tr: Sized { } +enum ImplicitSizing { + Sized, + DynSized, + None, +} + +impl ImplicitSizing { + fn implicitly_sized(&self) -> bool { + match *self { + ImplicitSizing::Sized => true, + ImplicitSizing::DynSized | ImplicitSizing::None => false, + } + } + + fn implicitly_dynsized(&self) -> bool { + match *self { + ImplicitSizing::Sized | ImplicitSizing::DynSized => true, + ImplicitSizing::None => false, + } + } +} + +fn find_implicit_sizing<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, + ast_bounds: &[hir::TyParamBound], + span: Span, + sized_by_default: SizedByDefault) -> ImplicitSizing { let tcx = astconv.tcx(); @@ -1300,27 +1325,36 @@ fn is_unsized<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, } } - let kind_id = tcx.lang_items().require(SizedTraitLangItem); - match unbound { - Some(ref tpb) => { - // FIXME(#8559) currently requires the unbound to be built-in. - if let Ok(kind_id) = kind_id { - if tpb.path.def != Def::Trait(kind_id) { - tcx.sess.span_warn(span, - "default bound relaxed for a type parameter, but \ - this does nothing because the given bound is not \ - a default. Only `?Sized` is supported"); - } + let sized_trait = tcx.lang_items().require(SizedTraitLangItem).map(Def::Trait); + let dynsized_trait = tcx.lang_items().require(DynSizedTraitLangItem).map(Def::Trait); + + let mut sizing = match sized_by_default { + SizedByDefault::Yes => ImplicitSizing::Sized, + SizedByDefault::No => ImplicitSizing::DynSized, + }; + + if let Some(ref tpb) = unbound { + if Ok(tpb.path.def) == sized_trait { + if sized_by_default == SizedByDefault::No { + let mut err = tcx.sess.struct_span_err(span, + "`?Sized` is not permitted in supertraits"); + + err.note("traits are `?Sized` by default"); + err.emit(); } + + sizing = ImplicitSizing::DynSized; + } else if Ok(tpb.path.def) == dynsized_trait { + sizing = ImplicitSizing::None; + } else { + tcx.sess.span_warn(span, + "default bound relaxed for a type parameter, but \ + this does nothing because the given bound is not \ + a default. Only `?Sized` and `?DynSized` are supported"); } - _ if kind_id.is_ok() => { - return false; - } - // No lang item for Sized, so we can't add it as a bound. - None => {} } - true + sizing } /// Returns the early-bound lifetimes declared in this generics @@ -1590,17 +1624,17 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -pub enum SizedByDefault { Yes, No, } +#[derive(PartialEq, Eq)] +enum SizedByDefault { Yes, No } /// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or /// a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the /// built-in trait (formerly known as kind): Send. -pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, - param_ty: Ty<'tcx>, - ast_bounds: &[hir::TyParamBound], - sized_by_default: SizedByDefault, - span: Span) - -> Bounds<'tcx> +fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, + param_ty: Ty<'tcx>, + ast_bounds: &[hir::TyParamBound], + sized_by_default: SizedByDefault, + span: Span) -> Bounds<'tcx> { let mut region_bounds = vec![]; let mut trait_bounds = vec![]; @@ -1630,15 +1664,12 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id())); - let implicitly_sized = if let SizedByDefault::Yes = sized_by_default { - !is_unsized(astconv, ast_bounds, span) - } else { - false - }; + let sizing = find_implicit_sizing(astconv, ast_bounds, span, sized_by_default); Bounds { region_bounds, - implicitly_sized, + implicitly_sized: sizing.implicitly_sized(), + implicitly_dynsized: sizing.implicitly_dynsized(), trait_bounds, projection_bounds, } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 37cc7a49b5271..0273bb1486bce 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -268,6 +268,7 @@ #![feature(core_float)] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] +#![feature(dynsized)] #![feature(exact_size_is_empty)] #![feature(fixed_size_array)] #![feature(float_from_str_radix)] diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 385076e50ddea..5a97db41cd5e3 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -22,6 +22,12 @@ use rc::Rc; use sync::{Arc, Mutex, RwLock, atomic}; use thread::Result; +#[cfg(stage0)] +use core::marker::Sized as DynSized; + +#[cfg(not(stage0))] +use core::marker::DynSized; + #[stable(feature = "panic_hooks", since = "1.10.0")] pub use panicking::{take_hook, set_hook, PanicInfo, Location}; @@ -101,6 +107,14 @@ pub use panicking::{take_hook, set_hook, PanicInfo, Location}; #[stable(feature = "catch_unwind", since = "1.9.0")] #[rustc_on_unimplemented = "the type {Self} may not be safely transferred \ across an unwind boundary"] +#[cfg(not(stage0))] +pub trait UnwindSafe: ?DynSized {} + +/// docs +#[stable(feature = "catch_unwind", since = "1.9.0")] +#[rustc_on_unimplemented = "the type {Self} may not be safely transferred \ + across an unwind boundary"] +#[cfg(stage0)] pub trait UnwindSafe {} /// A marker trait representing types where a shared reference is considered @@ -115,6 +129,15 @@ pub trait UnwindSafe {} #[rustc_on_unimplemented = "the type {Self} may contain interior mutability \ and a reference may not be safely transferrable \ across a catch_unwind boundary"] +#[cfg(not(stage0))] +pub trait RefUnwindSafe: ?DynSized {} + +/// docs +#[stable(feature = "catch_unwind", since = "1.9.0")] +#[rustc_on_unimplemented = "the type {Self} may contain interior mutability \ + and a reference may not be safely transferrable \ + across a catch_unwind boundary"] +#[cfg(stage0)] pub trait RefUnwindSafe {} /// A simple wrapper around a type to assert that it is unwind safe. @@ -192,13 +215,13 @@ pub struct AssertUnwindSafe( #[allow(auto_impl)] impl UnwindSafe for .. {} #[stable(feature = "catch_unwind", since = "1.9.0")] -impl<'a, T: ?Sized> !UnwindSafe for &'a mut T {} +impl<'a, T: ?DynSized> !UnwindSafe for &'a mut T {} #[stable(feature = "catch_unwind", since = "1.9.0")] -impl<'a, T: RefUnwindSafe + ?Sized> UnwindSafe for &'a T {} +impl<'a, T: RefUnwindSafe + ?DynSized> UnwindSafe for &'a T {} #[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for *const T {} +impl UnwindSafe for *const T {} #[stable(feature = "catch_unwind", since = "1.9.0")] -impl UnwindSafe for *mut T {} +impl UnwindSafe for *mut T {} #[unstable(feature = "unique", issue = "27730")] impl UnwindSafe for Unique {} #[unstable(feature = "shared", issue = "27730")] From 959e988f473dbe6b163719d79c74a912c121bf70 Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Fri, 8 Sep 2017 19:55:10 +0200 Subject: [PATCH 02/17] Make <*const T>::is_null() and al work with T: ?DynSized. --- src/libcore/ptr.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index a86db5cc85ae2..05782df40fcec 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -27,6 +27,13 @@ use nonzero::NonZero; use cmp::Ordering::{self, Less, Equal, Greater}; +#[cfg(stage0)] +use marker::Sized as DynSized; +#[cfg(not(stage0))] +use marker::DynSized; + +// FIXME #19649: intrinsic docs don't render, so these have no docs :( + #[stable(feature = "rust1", since = "1.0.0")] pub use intrinsics::copy_nonoverlapping; @@ -471,7 +478,7 @@ pub unsafe fn write_volatile(dst: *mut T, src: T) { } #[lang = "const_ptr"] -impl *const T { +impl *const T { /// Returns `true` if the pointer is null. /// /// # Examples @@ -1104,7 +1111,7 @@ impl *const T { } #[lang = "mut_ptr"] -impl *mut T { +impl *mut T { /// Returns `true` if the pointer is null. /// /// # Examples From e9639d1995c4dd923cf3ec466c76653482189ebd Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Fri, 8 Sep 2017 14:42:59 +0200 Subject: [PATCH 03/17] Fix tests for DynSized --- .../auxiliary/tdticc_coherence_lib.rs | 6 ++-- .../extern-types-not-sync-send.rs | 8 +++-- src/test/compile-fail/extern-types-unsized.rs | 23 +++--------- src/test/compile-fail/maybe-bounds.rs | 9 +++-- src/test/compile-fail/phantom-oibit.rs | 6 ++-- src/test/compile-fail/privacy-sanity.rs | 10 +++--- ...-default-trait-impl-constituent-types-2.rs | 6 ++-- ...ck-default-trait-impl-constituent-types.rs | 6 ++-- .../typeck-default-trait-impl-negation.rs | 8 +++-- .../typeck-default-trait-impl-precedence.rs | 6 ++-- .../run-pass/extern-types-manual-sync-send.rs | 8 +++-- .../run-pass/extern-types-pointer-cast.rs | 13 ------- src/test/run-pass/extern-types-size_of_val.rs | 26 -------------- .../run-pass/extern-types-thin-pointer.rs | 35 +++++-------------- src/test/run-pass/issue-29516.rs | 6 ++-- .../ui/on-unimplemented/multiple-impls.stderr | 26 +------------- src/test/ui/on-unimplemented/on-impl.stderr | 10 +----- 17 files changed, 66 insertions(+), 146 deletions(-) delete mode 100644 src/test/run-pass/extern-types-size_of_val.rs diff --git a/src/test/compile-fail/auxiliary/tdticc_coherence_lib.rs b/src/test/compile-fail/auxiliary/tdticc_coherence_lib.rs index 1e1c55de87e17..087367eaaf659 100644 --- a/src/test/compile-fail/auxiliary/tdticc_coherence_lib.rs +++ b/src/test/compile-fail/auxiliary/tdticc_coherence_lib.rs @@ -8,10 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(optin_builtin_traits, core)] +#![feature(dynsized, optin_builtin_traits)] #![crate_type = "rlib"] -pub trait DefaultedTrait { } +use std::marker::DynSized; + +pub trait DefaultedTrait: ?DynSized { } #[allow(auto_impl)] impl DefaultedTrait for .. { } diff --git a/src/test/compile-fail/extern-types-not-sync-send.rs b/src/test/compile-fail/extern-types-not-sync-send.rs index 2f00cf812e473..4e19215f0c513 100644 --- a/src/test/compile-fail/extern-types-not-sync-send.rs +++ b/src/test/compile-fail/extern-types-not-sync-send.rs @@ -10,14 +10,16 @@ // Make sure extern types are !Sync and !Send. -#![feature(extern_types)] +#![feature(dynsized, extern_types)] + +use std::marker::DynSized; extern { type A; } -fn assert_sync() { } -fn assert_send() { } +fn assert_sync() { } +fn assert_send() { } fn main() { assert_sync::(); diff --git a/src/test/compile-fail/extern-types-unsized.rs b/src/test/compile-fail/extern-types-unsized.rs index faa27894806f8..8a8df73171645 100644 --- a/src/test/compile-fail/extern-types-unsized.rs +++ b/src/test/compile-fail/extern-types-unsized.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Make sure extern types are !Sized. +// Make sure extern types are !Sized and !DynSized. #![feature(extern_types)] @@ -16,28 +16,13 @@ extern { type A; } -struct Foo { - x: u8, - tail: A, -} - -struct Bar { - x: u8, - tail: T, -} - fn assert_sized() { } +fn assert_dynsized() { } fn main() { assert_sized::(); //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied - assert_sized::(); - //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied - - assert_sized::>(); - //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied - - assert_sized::>>(); - //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied + assert_dynsized::(); + //~^ ERROR the trait bound `A: std::marker::DynSized` is not satisfied } diff --git a/src/test/compile-fail/maybe-bounds.rs b/src/test/compile-fail/maybe-bounds.rs index b0b412bbf89ec..743d636e4d94a 100644 --- a/src/test/compile-fail/maybe-bounds.rs +++ b/src/test/compile-fail/maybe-bounds.rs @@ -8,10 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -trait Tr: ?Sized {} //~ ERROR `?Trait` is not permitted in supertraits +#![feature(dynsized)] + +use std::marker::DynSized; + +trait Tr: ?Sized {} //~ ERROR `?Sized` is not permitted in supertraits //~^ NOTE traits are `?Sized` by default type A1 = Tr + ?Sized; //~ ERROR `?Trait` is not permitted in trait object types -type A2 = for<'a> Tr + ?Sized; //~ ERROR `?Trait` is not permitted in trait object types +type A2 = Tr + ?DynSized; //~ ERROR `?Trait` is not permitted in trait object types +type A3 = for<'a> Tr + ?Sized; //~ ERROR `?Trait` is not permitted in trait object types fn main() {} diff --git a/src/test/compile-fail/phantom-oibit.rs b/src/test/compile-fail/phantom-oibit.rs index 1c1cb396a54f2..140a77a3d26df 100644 --- a/src/test/compile-fail/phantom-oibit.rs +++ b/src/test/compile-fail/phantom-oibit.rs @@ -12,11 +12,11 @@ // the `PhantomData` type itself (which almost always implements a "default" trait // (`impl Trait for ..`)) -#![feature(optin_builtin_traits)] +#![feature(dynsized, optin_builtin_traits)] -use std::marker::{PhantomData}; +use std::marker::{DynSized, PhantomData}; -unsafe trait Zen {} +unsafe trait Zen: ?DynSized {} #[allow(auto_impl)] unsafe impl Zen for .. {} diff --git a/src/test/compile-fail/privacy-sanity.rs b/src/test/compile-fail/privacy-sanity.rs index 34082adb8f9a5..2e690e9508270 100644 --- a/src/test/compile-fail/privacy-sanity.rs +++ b/src/test/compile-fail/privacy-sanity.rs @@ -8,9 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(optin_builtin_traits)] +#![feature(dynsized, optin_builtin_traits)] -trait MarkerTr {} +use std::marker::DynSized; + +trait MarkerTr: ?DynSized {} pub trait Tr { fn f(); const C: u8; @@ -39,7 +41,7 @@ pub extern "C" { //~ ERROR unnecessary visibility qualifier } const MAIN: u8 = { - trait MarkerTr {} + trait MarkerTr: ?DynSized {} pub trait Tr { fn f(); const C: u8; @@ -71,7 +73,7 @@ const MAIN: u8 = { }; fn main() { - trait MarkerTr {} + trait MarkerTr: ?DynSized {} pub trait Tr { fn f(); const C: u8; diff --git a/src/test/compile-fail/typeck-default-trait-impl-constituent-types-2.rs b/src/test/compile-fail/typeck-default-trait-impl-constituent-types-2.rs index a837d8c9ca74e..78cc9e1fbe156 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-constituent-types-2.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-constituent-types-2.rs @@ -8,9 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(optin_builtin_traits)] +#![feature(dynsized, optin_builtin_traits)] -trait MyTrait {} +use std::marker::DynSized; + +trait MyTrait: ?DynSized {} #[allow(auto_impl)] impl MyTrait for .. {} diff --git a/src/test/compile-fail/typeck-default-trait-impl-constituent-types.rs b/src/test/compile-fail/typeck-default-trait-impl-constituent-types.rs index bed184eb4ccca..1e611d1475673 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-constituent-types.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-constituent-types.rs @@ -8,9 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(optin_builtin_traits)] +#![feature(dynsized, optin_builtin_traits)] -trait MyTrait {} +use std::marker::DynSized; + +trait MyTrait: ?DynSized {} #[allow(auto_impl)] impl MyTrait for .. {} diff --git a/src/test/compile-fail/typeck-default-trait-impl-negation.rs b/src/test/compile-fail/typeck-default-trait-impl-negation.rs index f3a6d8a342e22..ee707d7d9c46c 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-negation.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-negation.rs @@ -8,14 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(optin_builtin_traits)] +#![feature(dynsized, optin_builtin_traits)] -trait MyTrait {} +use std::marker::DynSized; + +trait MyTrait: ?DynSized {} #[allow(auto_impl)] impl MyTrait for .. {} -unsafe trait MyUnsafeTrait {} +unsafe trait MyUnsafeTrait: ?DynSized {} #[allow(auto_impl)] unsafe impl MyUnsafeTrait for .. {} diff --git a/src/test/compile-fail/typeck-default-trait-impl-precedence.rs b/src/test/compile-fail/typeck-default-trait-impl-precedence.rs index bdd6487b86d74..415b6002d21ed 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-precedence.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-precedence.rs @@ -13,9 +13,11 @@ // other words, the `..` impl only applies if there are no existing // impls whose types unify. -#![feature(optin_builtin_traits)] +#![feature(dynsized, optin_builtin_traits)] -trait Defaulted { } +use std::marker::DynSized; + +trait Defaulted: ?DynSized { } #[allow(auto_impl)] impl Defaulted for .. { } impl<'a,T:Signed> Defaulted for &'a T { } diff --git a/src/test/run-pass/extern-types-manual-sync-send.rs b/src/test/run-pass/extern-types-manual-sync-send.rs index c6530c3ea773a..113a02072b179 100644 --- a/src/test/run-pass/extern-types-manual-sync-send.rs +++ b/src/test/run-pass/extern-types-manual-sync-send.rs @@ -10,7 +10,9 @@ // Test that unsafe impl for Sync/Send can be provided for extern types. -#![feature(extern_types)] +#![feature(dynsized, extern_types)] + +use std::marker::DynSized; extern { type A; @@ -19,8 +21,8 @@ extern { unsafe impl Sync for A { } unsafe impl Send for A { } -fn assert_sync() { } -fn assert_send() { } +fn assert_sync() { } +fn assert_send() { } fn main() { assert_sync::(); diff --git a/src/test/run-pass/extern-types-pointer-cast.rs b/src/test/run-pass/extern-types-pointer-cast.rs index 628a570665a33..b53f98aa79a5a 100644 --- a/src/test/run-pass/extern-types-pointer-cast.rs +++ b/src/test/run-pass/extern-types-pointer-cast.rs @@ -17,16 +17,6 @@ extern { type A; } -struct Foo { - x: u8, - tail: A, -} - -struct Bar { - x: u8, - tail: T, -} - #[cfg(target_pointer_width = "32")] const MAGIC: usize = 0xdeadbeef; #[cfg(target_pointer_width = "64")] @@ -34,7 +24,4 @@ const MAGIC: usize = 0x12345678deadbeef; fn main() { assert_eq!((MAGIC as *const A) as usize, MAGIC); - assert_eq!((MAGIC as *const Foo) as usize, MAGIC); - assert_eq!((MAGIC as *const Bar) as usize, MAGIC); - assert_eq!((MAGIC as *const Bar>) as usize, MAGIC); } diff --git a/src/test/run-pass/extern-types-size_of_val.rs b/src/test/run-pass/extern-types-size_of_val.rs deleted file mode 100644 index 0aabce99debe8..0000000000000 --- a/src/test/run-pass/extern-types-size_of_val.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2017 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(extern_types)] - -use std::mem::{size_of_val, align_of_val}; - -extern { - type A; -} - -fn main() { - let x: &A = unsafe { - &*(1usize as *const A) - }; - - assert_eq!(size_of_val(x), 0); - assert_eq!(align_of_val(x), 1); -} diff --git a/src/test/run-pass/extern-types-thin-pointer.rs b/src/test/run-pass/extern-types-thin-pointer.rs index c2444a58b5a1b..477066585d256 100644 --- a/src/test/run-pass/extern-types-thin-pointer.rs +++ b/src/test/run-pass/extern-types-thin-pointer.rs @@ -19,33 +19,16 @@ extern { type A; } -struct Foo { - x: u8, - tail: A, -} - -struct Bar { - x: u8, - tail: T, -} - -fn assert_thin() { - assert_eq!(size_of::<*const T>(), size_of::<*const ()>()); - assert_eq!(align_of::<*const T>(), align_of::<*const ()>()); - - assert_eq!(size_of::<*mut T>(), size_of::<*mut ()>()); - assert_eq!(align_of::<*mut T>(), align_of::<*mut ()>()); +fn main() { + assert_eq!(size_of::<*const A>(), size_of::<*const ()>()); + assert_eq!(align_of::<*const A>(), align_of::<*const ()>()); - assert_eq!(size_of::<&T>(), size_of::<&()>()); - assert_eq!(align_of::<&T>(), align_of::<&()>()); + assert_eq!(size_of::<*mut A>(), size_of::<*mut ()>()); + assert_eq!(align_of::<*mut A>(), align_of::<*mut ()>()); - assert_eq!(size_of::<&mut T>(), size_of::<&mut ()>()); - assert_eq!(align_of::<&mut T>(), align_of::<&mut ()>()); -} + assert_eq!(size_of::<&A>(), size_of::<&()>()); + assert_eq!(align_of::<&A>(), align_of::<&()>()); -fn main() { - assert_thin::(); - assert_thin::(); - assert_thin::>(); - assert_thin::>>(); + assert_eq!(size_of::<&mut A>(), size_of::<&mut ()>()); + assert_eq!(align_of::<&mut A>(), align_of::<&mut ()>()); } diff --git a/src/test/run-pass/issue-29516.rs b/src/test/run-pass/issue-29516.rs index 5fa0a002a10db..3e9aa1168c9f3 100644 --- a/src/test/run-pass/issue-29516.rs +++ b/src/test/run-pass/issue-29516.rs @@ -8,9 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(optin_builtin_traits)] +#![feature(dynsized, optin_builtin_traits)] -trait NotSame {} +use std::marker::DynSized; + +trait NotSame: ?DynSized {} #[allow(auto_impl)] impl NotSame for .. {} impl !NotSame for (A, A) {} diff --git a/src/test/ui/on-unimplemented/multiple-impls.stderr b/src/test/ui/on-unimplemented/multiple-impls.stderr index a1fa8b720a829..d377f46547f48 100644 --- a/src/test/ui/on-unimplemented/multiple-impls.stderr +++ b/src/test/ui/on-unimplemented/multiple-impls.stderr @@ -7,14 +7,6 @@ error[E0277]: the trait bound `[i32]: Index` is not satisfied = help: the trait `Index` is not implemented for `[i32]` = note: required by `Index::index` -error[E0277]: the trait bound `[i32]: Index` is not satisfied - --> $DIR/multiple-impls.rs:43:5 - | -43 | Index::index(&[] as &[i32], 2u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait message - | - = help: the trait `Index` is not implemented for `[i32]` - error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:49:5 | @@ -24,14 +16,6 @@ error[E0277]: the trait bound `[i32]: Index>` is not satisfied = help: the trait `Index>` is not implemented for `[i32]` = note: required by `Index::index` -error[E0277]: the trait bound `[i32]: Index>` is not satisfied - --> $DIR/multiple-impls.rs:49:5 - | -49 | Index::index(&[] as &[i32], Foo(2u32)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ on impl for Foo - | - = help: the trait `Index>` is not implemented for `[i32]` - error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:55:5 | @@ -41,13 +25,5 @@ error[E0277]: the trait bound `[i32]: Index>` is not satisfied = help: the trait `Index>` is not implemented for `[i32]` = note: required by `Index::index` -error[E0277]: the trait bound `[i32]: Index>` is not satisfied - --> $DIR/multiple-impls.rs:55:5 - | -55 | Index::index(&[] as &[i32], Bar(2u32)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ on impl for Bar - | - = help: the trait `Index>` is not implemented for `[i32]` - -error: aborting due to 6 previous errors +error: aborting due to 3 previous errors diff --git a/src/test/ui/on-unimplemented/on-impl.stderr b/src/test/ui/on-unimplemented/on-impl.stderr index c8c06bf44fd6f..d3edc9dde8033 100644 --- a/src/test/ui/on-unimplemented/on-impl.stderr +++ b/src/test/ui/on-unimplemented/on-impl.stderr @@ -7,13 +7,5 @@ error[E0277]: the trait bound `[i32]: Index` is not satisfied = help: the trait `Index` is not implemented for `[i32]` = note: required by `Index::index` -error[E0277]: the trait bound `[i32]: Index` is not satisfied - --> $DIR/on-impl.rs:32:5 - | -32 | Index::::index(&[1, 2, 3] as &[i32], 2u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a usize is required to index into a slice - | - = help: the trait `Index` is not implemented for `[i32]` - -error: aborting due to 2 previous errors +error: aborting due to previous error From ec6809debe51e9c572a0bb6d5962d6e3a32060d5 Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Fri, 8 Sep 2017 19:28:21 +0200 Subject: [PATCH 04/17] Add DynSized related tests --- .../compile-fail/dynsized/no-manual-impl.rs | 25 +++++++++++++ src/test/compile-fail/dynsized/size_of_val.rs | 29 +++++++++++++++ .../dynsized/struct-last-field.rs | 36 +++++++++++++++++++ .../dynsized/supertait-unbound.rs | 28 +++++++++++++++ .../compile-fail/dynsized/tuple-last-field.rs | 28 +++++++++++++++ .../dynsized/sized-implies-dynsized.rs | 26 ++++++++++++++ .../run-pass/dynsized/supertrait-default.rs | 27 ++++++++++++++ 7 files changed, 199 insertions(+) create mode 100644 src/test/compile-fail/dynsized/no-manual-impl.rs create mode 100644 src/test/compile-fail/dynsized/size_of_val.rs create mode 100644 src/test/compile-fail/dynsized/struct-last-field.rs create mode 100644 src/test/compile-fail/dynsized/supertait-unbound.rs create mode 100644 src/test/compile-fail/dynsized/tuple-last-field.rs create mode 100644 src/test/run-pass/dynsized/sized-implies-dynsized.rs create mode 100644 src/test/run-pass/dynsized/supertrait-default.rs diff --git a/src/test/compile-fail/dynsized/no-manual-impl.rs b/src/test/compile-fail/dynsized/no-manual-impl.rs new file mode 100644 index 0000000000000..b591bc49246c1 --- /dev/null +++ b/src/test/compile-fail/dynsized/no-manual-impl.rs @@ -0,0 +1,25 @@ +// Copyright 2017 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 that DynSized cannot be implemented manually. + +#![feature(extern_types)] +#![feature(dynsized)] + +use std::marker::DynSized; + +extern { + type foo; +} + +impl DynSized for foo { } +//~^ ERROR explicit impls for the `DynSized` trait are not permitted + +fn main() { } diff --git a/src/test/compile-fail/dynsized/size_of_val.rs b/src/test/compile-fail/dynsized/size_of_val.rs new file mode 100644 index 0000000000000..756372978360e --- /dev/null +++ b/src/test/compile-fail/dynsized/size_of_val.rs @@ -0,0 +1,29 @@ +// Copyright 2017 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. + +// Ensure `size_of_val` / `align_of_val` can't be used on !DynSized types + +#![feature(extern_types)] + +use std::mem::{size_of_val, align_of_val}; + +extern { + type A; +} + +fn main() { + let x: &A = unsafe { + &*(1usize as *const A) + }; + + size_of_val(x); //~ERROR the trait bound `A: std::marker::DynSized` is not satisfied + + align_of_val(x); //~ERROR the trait bound `A: std::marker::DynSized` is not satisfied +} diff --git a/src/test/compile-fail/dynsized/struct-last-field.rs b/src/test/compile-fail/dynsized/struct-last-field.rs new file mode 100644 index 0000000000000..de27126748855 --- /dev/null +++ b/src/test/compile-fail/dynsized/struct-last-field.rs @@ -0,0 +1,36 @@ +// Copyright 2017 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. + +// Ensure !DynSized fields can't be used in structs, even as the last field. + +#![feature(extern_types)] +#![feature(dynsized)] + +use std::marker::DynSized; + +extern { + type foo; +} + +struct A { + x: foo, //~ERROR the trait bound `foo: std::marker::DynSized` is not satisfied +} + +struct B { + x: usize, + y: foo, //~ERROR the trait bound `foo: std::marker::DynSized` is not satisfied +} + +struct C { + x: usize, + y: T, //~ERROR the trait bound `T: std::marker::DynSized` is not satisfied +} + +fn main() { } diff --git a/src/test/compile-fail/dynsized/supertait-unbound.rs b/src/test/compile-fail/dynsized/supertait-unbound.rs new file mode 100644 index 0000000000000..e4d6ae3cbf213 --- /dev/null +++ b/src/test/compile-fail/dynsized/supertait-unbound.rs @@ -0,0 +1,28 @@ +// Copyright 2017 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 that traits can opt-out of being DynSized by default. +// See also run-pass/dynsized/supertrait-default.rs + +#![feature(dynsized)] + +use std::marker::DynSized; + +fn assert_dynsized() { } + +trait Tr: ?DynSized { + fn foo() { + assert_dynsized::(); + //~^ ERROR the trait bound `Self: std::marker::DynSized` is not satisfied + } +} + +fn main() { } + diff --git a/src/test/compile-fail/dynsized/tuple-last-field.rs b/src/test/compile-fail/dynsized/tuple-last-field.rs new file mode 100644 index 0000000000000..df86a100f90b4 --- /dev/null +++ b/src/test/compile-fail/dynsized/tuple-last-field.rs @@ -0,0 +1,28 @@ +// Copyright 2017 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. + +// Ensure !DynSized fields can't be used in tuples, even as the last field. + +#![feature(extern_types)] +#![feature(dynsized)] + +use std::marker::DynSized; + +extern { + type foo; +} + +fn baz() { + let x: &(u8, foo); //~ERROR the trait bound `foo: std::marker::DynSized` is not satisfied + + let y: &(u8, T); //~ERROR the trait bound `T: std::marker::DynSized` is not satisfied +} + +fn main() { } diff --git a/src/test/run-pass/dynsized/sized-implies-dynsized.rs b/src/test/run-pass/dynsized/sized-implies-dynsized.rs new file mode 100644 index 0000000000000..9aa61b4e6b595 --- /dev/null +++ b/src/test/run-pass/dynsized/sized-implies-dynsized.rs @@ -0,0 +1,26 @@ +// Copyright 2017 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(dynsized)] + +use std::marker::DynSized; + +fn foo() { +} + +fn bar() { + foo::(); +} + +fn baz() { + bar::(); +} + +fn main() { } diff --git a/src/test/run-pass/dynsized/supertrait-default.rs b/src/test/run-pass/dynsized/supertrait-default.rs new file mode 100644 index 0000000000000..dabc76112fe07 --- /dev/null +++ b/src/test/run-pass/dynsized/supertrait-default.rs @@ -0,0 +1,27 @@ +// Copyright 2017 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 that traits have DynSized as a super trait by default. +// See also compile-fail/dynsized/supertrait-unbound.rs + +#![feature(dynsized)] + +use std::marker::DynSized; + +fn assert_dynsized() { } + +trait Tr { + fn foo() { + assert_dynsized::(); + } +} + +fn main() { } + From 537da978e6bed499a3beca54b96ad422e951b27f Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Fri, 29 Sep 2017 20:50:57 +0200 Subject: [PATCH 05/17] Fix tidy errors --- src/librustc/util/ppaux.rs | 6 ++++-- src/librustc_passes/ast_validation.rs | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 03e0742cff5f6..127dcf022170b 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -1030,11 +1030,13 @@ define_print! { write!(f, "impl")?; for predicate in bounds.predicates { if let Some(trait_ref) = predicate.to_opt_poly_trait_ref() { + let did = trait_ref.def_id(); + // Don't print +Sized/DynSized, but rather +?Sized/?DynSized if absent. - if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() { + if Some(did) == tcx.lang_items().sized_trait() { is_sized = true; continue; - } else if Some(trait_ref.def_id()) == tcx.lang_items().dynsized_trait() { + } else if Some(did) == tcx.lang_items().dynsized_trait() { is_dynsized = true; continue; } diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 4085909705ee5..ed495e33f24dd 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -156,7 +156,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { any_lifetime_bounds = true; } TraitTyParamBound(ref poly, TraitBoundModifier::Maybe) => { - self.session.span_err(poly.span, "`?Trait` is not permitted in trait object types"); + self.session.span_err(poly.span, + "`?Trait` is not permitted in trait object types"); } _ => (), } From 76c66361ae7b638fa90156ccf764c43de83202d6 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sun, 19 Nov 2017 21:52:26 -0500 Subject: [PATCH 06/17] Fix typo by me --- src/librustc_trans/intrinsic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 185021e8da5b8..cf5ec2532c5a2 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -144,7 +144,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, } "size_of_val" => { let tp_ty = substs.type_at(0); - if bcx.ccx.shared().type_is_size(ty_ty) { + if bcx.ccx.shared().type_is_sized(tp_ty) { C_usize(ccx, ccx.size_of(tp_ty).bytes()) } else if bcx.ccx.shared().type_is_dynsized(tp_ty) { if let OperandValue::Pair(_, meta) = args[0].val { From 136cd109d123d7f9c34c701bb33826d69a2c5d25 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sun, 19 Nov 2017 21:54:02 -0500 Subject: [PATCH 07/17] add DynSized query variants to plumbing --- src/librustc/ty/maps/plumbing.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 1ca8fc6eb480f..b1680913ed6e3 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -724,6 +724,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, // these DepKind::IsCopy | DepKind::IsSized | + DepKind::IsDynSized | DepKind::IsFreeze | DepKind::NeedsDrop | DepKind::Layout | @@ -790,6 +791,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::IsConstFn => { force!(is_const_fn, def_id!()); } DepKind::IsForeignItem => { force!(is_foreign_item, def_id!()); } DepKind::SizedConstraint => { force!(adt_sized_constraint, def_id!()); } + DepKind::DynSizedConstraint => { force!(adt_dynsized_constraint, def_id!()); } DepKind::DtorckConstraint => { force!(adt_dtorck_constraint, def_id!()); } DepKind::AdtDestructor => { force!(adt_destructor, def_id!()); } DepKind::AssociatedItemDefIds => { force!(associated_item_def_ids, def_id!()); } From 0531eb5af72816061d953f5927744f0b2220484e Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sun, 19 Nov 2017 23:22:46 -0500 Subject: [PATCH 08/17] fix some auto_trait tests by removing the DynSized bound auto traits cannot have bounds, so they must remove the implicit DynSized bound with `Self: ?DynSized` --- src/test/compile-fail/auto-impl-future-compat.rs | 6 ++++-- src/test/run-pass/auto-traits.rs | 10 ++++++---- src/test/run-pass/extern-types-trait-impl.rs | 10 ++++++---- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/test/compile-fail/auto-impl-future-compat.rs b/src/test/compile-fail/auto-impl-future-compat.rs index 5c32a75639880..faaebe6fb53a4 100644 --- a/src/test/compile-fail/auto-impl-future-compat.rs +++ b/src/test/compile-fail/auto-impl-future-compat.rs @@ -8,9 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(optin_builtin_traits)] +#![feature(optin_builtin_traits, dynsized)] -trait Foo {} +use std::marker::DynSized; + +trait Foo: ?DynSized {} impl Foo for .. {} //~^ ERROR The form `impl Foo for .. {}` will be removed, please use `auto trait Foo {}` //~^^ WARN this was previously accepted by the compiler diff --git a/src/test/run-pass/auto-traits.rs b/src/test/run-pass/auto-traits.rs index e42aca9ccbd13..ce5668076368f 100644 --- a/src/test/run-pass/auto-traits.rs +++ b/src/test/run-pass/auto-traits.rs @@ -8,14 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(optin_builtin_traits)] +#![feature(optin_builtin_traits, dynsized)] -auto trait Auto {} +use std::marker::DynSized; + +auto trait Auto: ?DynSized {} // Redundant but accepted until we remove it. #[allow(auto_impl)] impl Auto for .. {} -unsafe auto trait AutoUnsafe {} +unsafe auto trait AutoUnsafe: ?DynSized {} impl !Auto for bool {} impl !AutoUnsafe for bool {} @@ -34,6 +36,6 @@ fn main() { take_auto_unsafe(0); take_auto_unsafe(AutoBool(true)); - /// Auto traits are allowed in trait object bounds. + // Auto traits are allowed in trait object bounds. let _: &(Send + Auto) = &0; } diff --git a/src/test/run-pass/extern-types-trait-impl.rs b/src/test/run-pass/extern-types-trait-impl.rs index 0f61c936deb61..15a80666da6da 100644 --- a/src/test/run-pass/extern-types-trait-impl.rs +++ b/src/test/run-pass/extern-types-trait-impl.rs @@ -10,13 +10,15 @@ // Test that traits can be implemented for extern types. -#![feature(extern_types)] +#![feature(extern_types, dynsized)] + +use std::marker::DynSized; extern { type A; } -trait Foo { +trait Foo: ?DynSized { fn foo(&self) { } } @@ -24,9 +26,9 @@ impl Foo for A { fn foo(&self) { } } -fn assert_foo() { } +fn assert_foo() { } -fn use_foo(x: &Foo) { +fn use_foo(x: &Foo) { x.foo(); } From fe40804064f016e140439d21035db0eda85ceb2b Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sun, 19 Nov 2017 23:37:25 -0500 Subject: [PATCH 09/17] allow ?Trait bounds in auto traits --- src/librustc_passes/ast_validation.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index ed495e33f24dd..7a76c967273f5 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -235,8 +235,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> { "auto traits cannot have generics"); } if !bounds.is_empty() { - self.err_handler().span_err(item.span, - "auto traits cannot have super traits"); + let all_bounds_are_maybe = bounds.iter() + .all(|bound| { + match *bound { + TraitTyParamBound(_, TraitBoundModifier::Maybe) => true, + _ => false + } + }); + + // allow `?DynSized` bound, since the `DynSized` bound is implicit + // for traits + if !all_bounds_are_maybe { + self.err_handler().span_err(item.span, + "auto traits cannot have super traits"); + } } if !trait_items.is_empty() { self.err_handler().span_err(item.span, From 38efc953c0b02ae054390a012e2d96ea22d5d25e Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sun, 19 Nov 2017 23:50:05 -0500 Subject: [PATCH 10/17] don't print `DynSized` in conflicting trait impl error messages This fixes a bunch of ui tests. It now either prints out `T`, `T: ?Sized`, or `T: ?DynSized`. --- src/librustc/traits/specialize/mod.rs | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index d8d0715ff3957..6c8e506a85888 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -374,13 +374,16 @@ fn to_pretty_impl_header(tcx: TyCtxt, impl_def_id: DefId) -> Option { let substs = Substs::identity_for_item(tcx, impl_def_id); - // FIXME: Currently only handles ?Sized. - // Needs to support ?Move and ?DynSized when they are implemented. - let mut types_without_default_bounds = FxHashSet::default(); + // FIXME: Currently only handles ?Sized and ?DynSized. + // Needs to support ?Move when it is implemented. + let mut types_without_sized = FxHashSet::default(); + let mut types_without_dynsized = FxHashSet::default(); let sized_trait = tcx.lang_items().sized_trait(); + let dynsized_trait = tcx.lang_items().dynsized_trait(); if !substs.is_noop() { - types_without_default_bounds.extend(substs.types()); + types_without_sized.extend(substs.types()); + types_without_dynsized.extend(substs.types()); w.push('<'); w.push_str(&substs.iter().map(|k| k.to_string()).collect::>().join(", ")); w.push('>'); @@ -395,14 +398,22 @@ fn to_pretty_impl_header(tcx: TyCtxt, impl_def_id: DefId) -> Option { for p in predicates { if let Some(poly_trait_ref) = p.to_opt_poly_trait_ref() { if Some(poly_trait_ref.def_id()) == sized_trait { - types_without_default_bounds.remove(poly_trait_ref.self_ty()); + types_without_sized.remove(poly_trait_ref.self_ty()); + continue; + } + if Some(poly_trait_ref.def_id()) == dynsized_trait { + types_without_dynsized.remove(poly_trait_ref.self_ty()); continue; } } pretty_predicates.push(p.to_string()); } - for ty in types_without_default_bounds { - pretty_predicates.push(format!("{}: ?Sized", ty)); + for ty in types_without_sized { + if types_without_dynsized.contains(&ty) { + pretty_predicates.push(format!("{}: ?DynSized", ty)); + } else { + pretty_predicates.push(format!("{}: ?Sized", ty)); + } } if !pretty_predicates.is_empty() { write!(w, "\n where {}", pretty_predicates.join(", ")).unwrap(); From 76b20861eba280994ad3ba685660ac291ff106e5 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Mon, 20 Nov 2017 00:13:07 -0500 Subject: [PATCH 11/17] don't bug! if the unsized struct tail isn't [T], str, or a trait object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are other types that can be in a DST struct’s tail: other DST structs, DST tuples, and possibly more. The only one we don’t want to allow is extern types, so I added a check for that --- src/librustc_trans/mir/lvalue.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index 111794d3ab86f..f3188486d3c5e 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -239,12 +239,13 @@ impl<'a, 'tcx> LvalueRef<'tcx> { return simple(); } - // If the type of the last field is [T] or str, then we don't need to do - // any adjusments. Otherwise it must be a trait object. match field.ty.sty { + // If the type of the last field is [T] or str, then we don't need + // to do any adjustments. ty::TySlice(..) | ty::TyStr => return simple(), - ty::TyDynamic(..) => (), - _ => bug!("unexpected DST tail: {:?}", fty.sty), + // extern types aren't allowed in struct tails, this is a bug + ty::TyForeign(..) => bug!("extern type in a struct field"), + _ => () } // We need to get the pointer manually now. From 83cffc8406a60f557ef1e6643637d7cc574ebfea Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Mon, 20 Nov 2017 00:14:18 -0500 Subject: [PATCH 12/17] shorten line for tidy --- src/librustc/util/ppaux.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 127dcf022170b..0b5a4a1549701 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -1032,10 +1032,11 @@ define_print! { if let Some(trait_ref) = predicate.to_opt_poly_trait_ref() { let did = trait_ref.def_id(); - // Don't print +Sized/DynSized, but rather +?Sized/?DynSized if absent. + // Don't print Sized, but rather ?Sized if absent. if Some(did) == tcx.lang_items().sized_trait() { is_sized = true; continue; + // Same for DynSized } else if Some(did) == tcx.lang_items().dynsized_trait() { is_dynsized = true; continue; From 76ab6105778d4812360df41061ee33eec05ea1c7 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Mon, 20 Nov 2017 02:03:05 -0500 Subject: [PATCH 13/17] fix run-make/simd-ffi test had to add the dynsized lang item, and add ?DynSized bound to auto traits --- src/test/run-make/simd-ffi/simd.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/test/run-make/simd-ffi/simd.rs b/src/test/run-make/simd-ffi/simd.rs index 185476fb704f7..2ae715f925c47 100644 --- a/src/test/run-make/simd-ffi/simd.rs +++ b/src/test/run-make/simd-ffi/simd.rs @@ -72,6 +72,9 @@ pub fn bar(a: i32x4, b: i32x4) -> i32x4 { #[lang = "sized"] pub trait Sized { } +#[lang = "dynsized"] +pub trait DynSized: ?DynSized { } + #[lang = "copy"] pub trait Copy { } @@ -80,6 +83,6 @@ pub mod marker { } #[lang = "freeze"] -trait Freeze {} +trait Freeze: ?DynSized {} #[allow(auto_impl)] impl Freeze for .. {} From d308beefa3f2625532901231982bfd4d14bd8732 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Mon, 20 Nov 2017 13:53:34 -0500 Subject: [PATCH 14/17] add ?Dynsized support to rustic --- src/librustdoc/clean/mod.rs | 93 ++++++++++++++++++++++++++++++------- 1 file changed, 77 insertions(+), 16 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1d107c169b046..09aeb51e7e68c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -734,6 +734,33 @@ impl TyParamBound { } false } + + fn maybe_dynsized(cx: &DocContext) -> TyParamBound { + let did = cx.tcx.require_lang_item(lang_items::DynSizedTraitLangItem); + let empty = cx.tcx.intern_substs(&[]); + let path = external_path(cx, &cx.tcx.item_name(did), + Some(did), false, vec![], empty); + inline::record_extern_fqn(cx, did, TypeKind::Trait); + TraitBound(PolyTrait { + trait_: ResolvedPath { + path, + typarams: None, + did, + is_generic: false, + }, + lifetimes: vec![] + }, hir::TraitBoundModifier::Maybe) + } + + fn is_dynsized_bound(&self, cx: &DocContext) -> bool { + use rustc::hir::TraitBoundModifier as TBM; + if let TyParamBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self { + if trait_.def_id() == cx.tcx.lang_items().dynsized_trait() { + return true; + } + } + false + } } impl Clean for hir::TyParamBound { @@ -1089,29 +1116,35 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, let mut where_predicates = preds.predicates.to_vec().clean(cx); - // Type parameters and have a Sized bound by default unless removed with - // ?Sized. Scan through the predicates and mark any type parameter with - // a Sized bound, removing the bounds as we find them. + // Type parameters have a Sized bound by default unless removed with + // ?Sized or ?DynSized. Scan through the predicates and mark any type parameter with + // a Sized or DynSized bound, removing the bounds as we find them. // // Note that associated types also have a sized bound by default, but we // don't actually know the set of associated types right here so that's // handled in cleaning associated types let mut sized_params = FxHashSet(); + let mut dynsized_params = FxHashSet(); where_predicates.retain(|pred| { match *pred { WP::BoundPredicate { ty: Generic(ref g), ref bounds } => { - if bounds.iter().any(|b| b.is_sized_bound(cx)) { - sized_params.insert(g.clone()); - false - } else { - true + let mut retain = true; + for bound in bounds.iter() { + if bound.is_sized_bound(cx) { + sized_params.insert(g.clone()); + retain = false; + } else if bound.is_dynsized_bound(cx) { + dynsized_params.insert(g.clone()); + retain = false; + } } + retain } _ => true, } }); - // Run through the type parameters again and insert a ?Sized + // Run through the type parameters again and insert a ?Sized or ?DynSized // unbound for any we didn't find to be Sized. for tp in &stripped_typarams { if !sized_params.contains(&tp.name) { @@ -1119,6 +1152,11 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, ty: Type::Generic(tp.name.clone()), bounds: vec![TyParamBound::maybe_sized(cx)], }) + } else if !dynsized_params.contains(&tp.name) { + where_predicates.push(WP::BoundPredicate { + ty: Type::Generic(tp.name.clone()), + bounds: vec![TyParamBound::maybe_dynsized(cx)], + }) } } @@ -1532,14 +1570,37 @@ impl<'tcx> Clean for ty::AssociatedItem { vec![] }; - // Our Sized/?Sized bound didn't get handled when creating the generics + // Our Sized/?Sized/?DynSized bound didn't get handled when creating the generics // because we didn't actually get our whole set of bounds until just now - // (some of them may have come from the trait). If we do have a sized - // bound, we remove it, and if we don't then we add the `?Sized` bound - // at the end. - match bounds.iter().position(|b| b.is_sized_bound(cx)) { - Some(i) => { bounds.remove(i); } - None => bounds.push(TyParamBound::maybe_sized(cx)), + // (some of them may have come from the trait). + // + // We remove `Sized` and `DynSized` bounds, and then possibly add `?Sized` + // or `?DynSized`. + // + // It's theoretically possible to have a `Sized` bound without a `DynSized` bound. + // It means the same as having both, since `DynSized` is a supertrait of `Sized` + let mut has_sized_bound = false; + let mut has_dynsized_bound = false; + bounds.retain(|bound| { + if bound.is_sized_bound(cx) { + has_sized_bound = true; + false + } else if bound.is_dynsized_bound(cx) { + has_dynsized_bound = true; + false + } else { + true + } + }); + if has_sized_bound { + // T + // don't push anything + } else if has_dynsized_bound { + // T: ?Sized + bounds.push(TyParamBound::maybe_sized(cx)); + } else { + // T: ?DynSized + bounds.push(TyParamBound::maybe_dynsized(cx)); } let ty = if self.defaultness.has_value() { From a36e2fe3f99fb945270a548b83f8945c35fd8980 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Mon, 20 Nov 2017 13:54:22 -0500 Subject: [PATCH 15/17] fix some rustdoc tests Had to add ?DynSized to auto-traits --- src/test/rustdoc/auxiliary/rustdoc-default-impl.rs | 6 +++--- src/test/rustdoc/auxiliary/rustdoc-impl-parts-crosscrate.rs | 6 ++++-- src/test/rustdoc/impl-parts.rs | 6 ++++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs b/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs index 4fd55bd482cd9..045164c8ef000 100644 --- a/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs +++ b/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs @@ -8,13 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(optin_builtin_traits)] +#![feature(optin_builtin_traits, dynsized)] #![feature(core)] pub mod bar { - use std::marker; + use std::marker::DynSized; - pub trait Bar {} + pub trait Bar: ?DynSized {} #[allow(auto_impl)] impl Bar for .. {} diff --git a/src/test/rustdoc/auxiliary/rustdoc-impl-parts-crosscrate.rs b/src/test/rustdoc/auxiliary/rustdoc-impl-parts-crosscrate.rs index d886778278dfd..cb8b83d27942b 100644 --- a/src/test/rustdoc/auxiliary/rustdoc-impl-parts-crosscrate.rs +++ b/src/test/rustdoc/auxiliary/rustdoc-impl-parts-crosscrate.rs @@ -8,9 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(optin_builtin_traits)] +#![feature(optin_builtin_traits, dynsized)] -pub trait AnOibit {} +use std::marker::DynSized; + +pub trait AnOibit: ?DynSized {} #[allow(auto_impl)] impl AnOibit for .. {} diff --git a/src/test/rustdoc/impl-parts.rs b/src/test/rustdoc/impl-parts.rs index f74f66ce72905..34c0a4be55d6c 100644 --- a/src/test/rustdoc/impl-parts.rs +++ b/src/test/rustdoc/impl-parts.rs @@ -8,9 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(optin_builtin_traits)] +#![feature(optin_builtin_traits, dynsized)] -pub trait AnOibit {} +use std::marker::DynSized; + +pub trait AnOibit: ?DynSized {} #[allow(auto_impl)] impl AnOibit for .. {} From 62b4c9131244b7b1017fda9426fa47cafe7f7b51 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Mon, 20 Nov 2017 15:04:29 -0500 Subject: [PATCH 16/17] Update auto traits in the unstable book Add a `?DynSized` unbound to the auto trait in the example, and explain why it is necessary --- .../src/language-features/optin-builtin-traits.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/doc/unstable-book/src/language-features/optin-builtin-traits.md b/src/doc/unstable-book/src/language-features/optin-builtin-traits.md index 97b57c690fcc8..07729e2b79e66 100644 --- a/src/doc/unstable-book/src/language-features/optin-builtin-traits.md +++ b/src/doc/unstable-book/src/language-features/optin-builtin-traits.md @@ -19,12 +19,22 @@ has explictly opted out via a negative impl. impl !Type for Trait ``` +[#46108] added the `DynSized` trait, which is an implicit bound for all traits. Auto traits may not +have bounds, so you must explicitly remove this bound with `?DynSized`. [#44917] adds a `Move` trait +which is also implicit, so when that lands, you will have to add `?Move` as well. + +[#46108]: https://github.com/rust-lang/rust/pull/46108 +[#44917]: https://github.com/rust-lang/rust/pull/44917 + + Example: ```rust -#![feature(optin_builtin_traits)] +#![feature(optin_builtin_traits, dynsized)] + +use std::marker::DynSized; -auto trait Valid {} +auto trait Valid: ?DynSized {} struct True; struct False; @@ -38,7 +48,6 @@ fn must_be_valid(_t: T) { } fn main() { // works must_be_valid( MaybeValid(True) ); - // compiler error - trait bound not satisfied // must_be_valid( MaybeValid(False) ); } From b9a69c7c4a72c7cb453d81f06b5dede0d1f43961 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Mon, 20 Nov 2017 19:11:10 -0500 Subject: [PATCH 17/17] Fix src/test/rustdoc/foreigntype.rs extern types do not implement DynSized, so to implement a trait for one you need to explicitly remove the DynSized bound for that trait --- src/test/rustdoc/foreigntype.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/test/rustdoc/foreigntype.rs b/src/test/rustdoc/foreigntype.rs index 06447ffaa753d..2547fd9882627 100644 --- a/src/test/rustdoc/foreigntype.rs +++ b/src/test/rustdoc/foreigntype.rs @@ -8,7 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(extern_types)] +#![feature(extern_types, dynsized)] + +use std::marker::DynSized; extern { // @has foreigntype/foreigntype.ExtType.html @@ -20,7 +22,7 @@ impl ExtType { pub fn do_something(&self) {} } -pub trait Trait {} +pub trait Trait: ?DynSized {} // @has foreigntype/trait.Trait.html '//a[@class="foreigntype"]' 'ExtType' impl Trait for ExtType {}