Skip to content

Commit a18bd5a

Browse files
plietarmikeyhew
authored andcommitted
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 rust-lang#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<T: ?Sized> { a_x: u8 a_y: T } struct B<T: ?Sized> { b_x: u8 b_y: T } ``` Before this change, the type `A<B<foo>>` is considered well-formed. However, the alignment of `B<foo>` 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<B<foo>>` ill-formed. Just like the `Sized` trait, the default bound can be opted-out by using `?DynSized`.
1 parent 33374fa commit a18bd5a

File tree

25 files changed

+470
-112
lines changed

25 files changed

+470
-112
lines changed

src/libcore/marker.rs

+72-25
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ use hash::Hasher;
4040
/// [ub]: ../../reference/behavior-considered-undefined.html
4141
#[stable(feature = "rust1", since = "1.0.0")]
4242
#[cfg_attr(stage0, lang = "send")]
43+
#[cfg(not(stage0))]
44+
#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"]
45+
pub unsafe trait Send: ?DynSized {
46+
// empty.
47+
}
48+
49+
/// docs
50+
#[stable(feature = "rust1", since = "1.0.0")]
51+
#[cfg_attr(stage0, lang = "send")]
52+
#[cfg(stage0)]
4353
#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"]
4454
pub unsafe trait Send {
4555
// empty.
@@ -51,9 +61,9 @@ pub unsafe trait Send {
5161
unsafe impl Send for .. { }
5262

5363
#[stable(feature = "rust1", since = "1.0.0")]
54-
impl<T: ?Sized> !Send for *const T { }
64+
impl<T: ?DynSized> !Send for *const T { }
5565
#[stable(feature = "rust1", since = "1.0.0")]
56-
impl<T: ?Sized> !Send for *mut T { }
66+
impl<T: ?DynSized> !Send for *mut T { }
5767

5868
/// Types with a constant size known at compile time.
5969
///
@@ -96,6 +106,29 @@ pub trait Sized {
96106
// Empty.
97107
}
98108

109+
/// Types with a size known at run time.
110+
///
111+
/// This trait is implemented both by `Sized` types, and by dynamically sized
112+
/// types such as slices and [trait objects]. [Extern types], whose size is not
113+
/// known, even at runtime, do not implement this trait.
114+
///
115+
/// All traits and type parameters have an implicit bound of `DynSized`. The
116+
/// special syntax `?DynSized` can be used to remove this bound if it's not
117+
/// appropriate.
118+
///
119+
/// [trait object]: ../../book/first-edition/trait-objects.html
120+
#[cfg(not(stage0))]
121+
#[unstable(feature = "dynsized", issue = "0")]
122+
#[lang = "dynsized"]
123+
#[rustc_on_unimplemented = "`{Self}` does not have a size known at run-time"]
124+
#[fundamental]
125+
pub trait DynSized: ?DynSized {
126+
// Empty.
127+
}
128+
129+
#[cfg(stage0)]
130+
use self::Sized as DynSized; // This is just so we don't have to stage too much stuff
131+
99132
/// Types that can be "unsized" to a dynamically-sized type.
100133
///
101134
/// For example, the sized array type `[i8; 2]` implements `Unsize<[i8]>` and
@@ -345,6 +378,16 @@ pub trait Copy : Clone {
345378
/// [transmute]: ../../std/mem/fn.transmute.html
346379
#[stable(feature = "rust1", since = "1.0.0")]
347380
#[lang = "sync"]
381+
#[cfg(not(stage0))]
382+
#[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"]
383+
pub unsafe trait Sync: ?DynSized {
384+
// Empty
385+
}
386+
387+
/// docs
388+
#[stable(feature = "rust1", since = "1.0.0")]
389+
#[lang = "sync"]
390+
#[cfg(stage0)]
348391
#[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"]
349392
pub unsafe trait Sync {
350393
// Empty
@@ -356,56 +399,56 @@ pub unsafe trait Sync {
356399
unsafe impl Sync for .. { }
357400

358401
#[stable(feature = "rust1", since = "1.0.0")]
359-
impl<T: ?Sized> !Sync for *const T { }
402+
impl<T: ?DynSized> !Sync for *const T { }
360403
#[stable(feature = "rust1", since = "1.0.0")]
361-
impl<T: ?Sized> !Sync for *mut T { }
404+
impl<T: ?DynSized> !Sync for *mut T { }
362405

363406
macro_rules! impls{
364407
($t: ident) => (
365408
#[stable(feature = "rust1", since = "1.0.0")]
366-
impl<T:?Sized> Hash for $t<T> {
409+
impl<T:?DynSized> Hash for $t<T> {
367410
#[inline]
368411
fn hash<H: Hasher>(&self, _: &mut H) {
369412
}
370413
}
371414

372415
#[stable(feature = "rust1", since = "1.0.0")]
373-
impl<T:?Sized> cmp::PartialEq for $t<T> {
416+
impl<T:?DynSized> cmp::PartialEq for $t<T> {
374417
fn eq(&self, _other: &$t<T>) -> bool {
375418
true
376419
}
377420
}
378421

379422
#[stable(feature = "rust1", since = "1.0.0")]
380-
impl<T:?Sized> cmp::Eq for $t<T> {
423+
impl<T:?DynSized> cmp::Eq for $t<T> {
381424
}
382425

383426
#[stable(feature = "rust1", since = "1.0.0")]
384-
impl<T:?Sized> cmp::PartialOrd for $t<T> {
427+
impl<T:?DynSized> cmp::PartialOrd for $t<T> {
385428
fn partial_cmp(&self, _other: &$t<T>) -> Option<cmp::Ordering> {
386429
Option::Some(cmp::Ordering::Equal)
387430
}
388431
}
389432

390433
#[stable(feature = "rust1", since = "1.0.0")]
391-
impl<T:?Sized> cmp::Ord for $t<T> {
434+
impl<T:?DynSized> cmp::Ord for $t<T> {
392435
fn cmp(&self, _other: &$t<T>) -> cmp::Ordering {
393436
cmp::Ordering::Equal
394437
}
395438
}
396439

397440
#[stable(feature = "rust1", since = "1.0.0")]
398-
impl<T:?Sized> Copy for $t<T> { }
441+
impl<T:?DynSized> Copy for $t<T> { }
399442

400443
#[stable(feature = "rust1", since = "1.0.0")]
401-
impl<T:?Sized> Clone for $t<T> {
444+
impl<T:?DynSized> Clone for $t<T> {
402445
fn clone(&self) -> $t<T> {
403446
$t
404447
}
405448
}
406449

407450
#[stable(feature = "rust1", since = "1.0.0")]
408-
impl<T:?Sized> Default for $t<T> {
451+
impl<T:?DynSized> Default for $t<T> {
409452
fn default() -> $t<T> {
410453
$t
411454
}
@@ -548,31 +591,35 @@ macro_rules! impls{
548591
/// [drop check]: ../../nomicon/dropck.html
549592
#[lang = "phantom_data"]
550593
#[stable(feature = "rust1", since = "1.0.0")]
551-
pub struct PhantomData<T:?Sized>;
594+
pub struct PhantomData<T:?DynSized>;
552595

553596
impls! { PhantomData }
554597

555-
mod impls {
556-
#[stable(feature = "rust1", since = "1.0.0")]
557-
unsafe impl<'a, T: Sync + ?Sized> Send for &'a T {}
558-
#[stable(feature = "rust1", since = "1.0.0")]
559-
unsafe impl<'a, T: Send + ?Sized> Send for &'a mut T {}
560-
}
598+
#[stable(feature = "rust1", since = "1.0.0")]
599+
unsafe impl<'a, T: Sync + ?DynSized> Send for &'a T {}
600+
#[stable(feature = "rust1", since = "1.0.0")]
601+
unsafe impl<'a, T: Send + ?DynSized> Send for &'a mut T {}
561602

562603
/// Compiler-internal trait used to determine whether a type contains
563604
/// any `UnsafeCell` internally, but not through an indirection.
564605
/// This affects, for example, whether a `static` of that type is
565606
/// placed in read-only static memory or writable static memory.
566607
#[lang = "freeze"]
608+
#[cfg(not(stage0))]
609+
unsafe trait Freeze: ?DynSized {}
610+
611+
/// docs
612+
#[lang = "freeze"]
613+
#[cfg(stage0)]
567614
unsafe trait Freeze {}
568615

569616
#[allow(unknown_lints)]
570617
#[allow(auto_impl)]
571618
unsafe impl Freeze for .. {}
572619

573-
impl<T: ?Sized> !Freeze for UnsafeCell<T> {}
574-
unsafe impl<T: ?Sized> Freeze for PhantomData<T> {}
575-
unsafe impl<T: ?Sized> Freeze for *const T {}
576-
unsafe impl<T: ?Sized> Freeze for *mut T {}
577-
unsafe impl<'a, T: ?Sized> Freeze for &'a T {}
578-
unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {}
620+
impl<T: ?DynSized> !Freeze for UnsafeCell<T> {}
621+
unsafe impl<T: ?DynSized> Freeze for PhantomData<T> {}
622+
unsafe impl<T: ?DynSized> Freeze for *const T {}
623+
unsafe impl<T: ?DynSized> Freeze for *mut T {}
624+
unsafe impl<'a, T: ?DynSized> Freeze for &'a T {}
625+
unsafe impl<'a, T: ?DynSized> Freeze for &'a mut T {}

src/libcore/ptr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ pub use intrinsics::write_bytes;
5656
#[stable(feature = "drop_in_place", since = "1.8.0")]
5757
#[lang = "drop_in_place"]
5858
#[allow(unconditional_recursion)]
59-
pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
59+
pub unsafe fn drop_in_place<T: ?DynSized>(to_drop: *mut T) {
6060
// Code here does not matter - this is replaced by the
6161
// real drop glue by the compiler.
6262
drop_in_place(to_drop);

src/librustc/dep_graph/dep_node.rs

+2
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,7 @@ define_dep_nodes!( <'tcx>
509509
[] IsForeignItem(DefId),
510510
[] TypeParamPredicates { item_id: DefId, param_id: DefId },
511511
[] SizedConstraint(DefId),
512+
[] DynSizedConstraint(DefId),
512513
[] DtorckConstraint(DefId),
513514
[] AdtDestructor(DefId),
514515
[] AssociatedItemDefIds(DefId),
@@ -527,6 +528,7 @@ define_dep_nodes!( <'tcx>
527528

528529
[] IsCopy { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> },
529530
[] IsSized { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> },
531+
[] IsDynSized { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> },
530532
[] IsFreeze { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> },
531533
[] NeedsDrop { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> },
532534
[] Layout { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> },

src/librustc/middle/lang_items.rs

+1
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ language_item_table! {
230230
F64ImplItem, "f64", f64_impl;
231231

232232
SizedTraitLangItem, "sized", sized_trait;
233+
DynSizedTraitLangItem, "dynsized", dynsized_trait;
233234
UnsizeTraitLangItem, "unsize", unsize_trait;
234235
CopyTraitLangItem, "copy", copy_trait;
235236
CloneTraitLangItem, "clone", clone_trait;

src/librustc/traits/error_reporting.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1243,6 +1243,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
12431243
ObligationCauseCode::StructInitializerSized => {
12441244
err.note("structs must have a statically known size to be initialized");
12451245
}
1246+
ObligationCauseCode::FieldDynSized => {
1247+
err.note("the last field of a struct or tuple must have a dynamically sized type");
1248+
}
12461249
ObligationCauseCode::FieldSized(ref item) => {
12471250
match *item {
12481251
AdtKind::Struct => {

src/librustc/traits/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ pub enum ObligationCauseCode<'tcx> {
137137
/// Types of fields (other than the last) in a struct must be sized.
138138
FieldSized(AdtKind),
139139

140+
/// Last field of a struct must be DynSized.
141+
FieldDynSized,
142+
140143
/// Constant expressions must be sized.
141144
ConstSized,
142145

src/librustc/traits/select.rs

+56
Original file line numberDiff line numberDiff line change
@@ -1348,6 +1348,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
13481348
let sized_conditions = self.sized_conditions(obligation);
13491349
self.assemble_builtin_bound_candidates(sized_conditions,
13501350
&mut candidates)?;
1351+
} else if lang_items.dynsized_trait() == Some(def_id) {
1352+
// DynSized is never implementable by end-users, it is
1353+
// always automatically computed.
1354+
let dynsized_conditions = self.dynsized_conditions(obligation);
1355+
self.assemble_builtin_bound_candidates(dynsized_conditions,
1356+
&mut candidates)?;
13511357
} else if lang_items.unsize_trait() == Some(def_id) {
13521358
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
13531359
} else {
@@ -2054,6 +2060,53 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
20542060
}
20552061
}
20562062

2063+
fn dynsized_conditions(&mut self, obligation: &TraitObligation<'tcx>)
2064+
-> BuiltinImplConditions<'tcx>
2065+
{
2066+
use self::BuiltinImplConditions::{Ambiguous, None, Never, Where};
2067+
2068+
// NOTE: binder moved to (*)
2069+
let self_ty = self.infcx.shallow_resolve(
2070+
obligation.predicate.skip_binder().self_ty());
2071+
2072+
match self_ty.sty {
2073+
ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) |
2074+
ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) |
2075+
ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyRawPtr(..) |
2076+
ty::TyChar | ty::TyRef(..) | ty::TyGenerator(..) |
2077+
ty::TyArray(..) | ty::TyClosure(..) | ty::TyNever |
2078+
ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) |
2079+
ty::TyError => {
2080+
// safe for everything
2081+
Where(ty::Binder(Vec::new()))
2082+
}
2083+
2084+
ty::TyTuple(tys, _) => {
2085+
Where(ty::Binder(tys.last().into_iter().cloned().collect()))
2086+
}
2087+
2088+
ty::TyAdt(def, substs) => {
2089+
let dynsized_crit = def.dynsized_constraint(self.tcx());
2090+
// (*) binder moved here
2091+
Where(ty::Binder(
2092+
dynsized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect()
2093+
))
2094+
}
2095+
2096+
ty::TyForeign(..) => Never,
2097+
2098+
ty::TyProjection(_) | ty::TyParam(_) | ty::TyAnon(..) => None,
2099+
ty::TyInfer(ty::TyVar(_)) => Ambiguous,
2100+
2101+
ty::TyInfer(ty::FreshTy(_))
2102+
| ty::TyInfer(ty::FreshIntTy(_))
2103+
| ty::TyInfer(ty::FreshFloatTy(_)) => {
2104+
bug!("asked to assemble builtin bounds of unexpected type: {:?}",
2105+
self_ty);
2106+
}
2107+
}
2108+
}
2109+
20572110
fn copy_clone_conditions(&mut self, obligation: &TraitObligation<'tcx>)
20582111
-> BuiltinImplConditions<'tcx>
20592112
{
@@ -2382,6 +2435,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
23822435
_ if Some(trait_def) == lang_items.sized_trait() => {
23832436
self.sized_conditions(obligation)
23842437
}
2438+
_ if Some(trait_def) == lang_items.dynsized_trait() => {
2439+
self.dynsized_conditions(obligation)
2440+
}
23852441
_ if Some(trait_def) == lang_items.copy_trait() => {
23862442
self.copy_clone_conditions(obligation)
23872443
}

src/librustc/traits/structural_impls.rs

+3
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
204204
super::SizedReturnType => Some(super::SizedReturnType),
205205
super::RepeatVec => Some(super::RepeatVec),
206206
super::FieldSized(item) => Some(super::FieldSized(item)),
207+
super::FieldDynSized => Some(super::FieldDynSized),
207208
super::ConstSized => Some(super::ConstSized),
208209
super::SharedStatic => Some(super::SharedStatic),
209210
super::BuiltinDerivedObligation(ref cause) => {
@@ -522,6 +523,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
522523
super::ReturnNoExpression |
523524
super::RepeatVec |
524525
super::FieldSized(_) |
526+
super::FieldDynSized |
525527
super::ConstSized |
526528
super::SharedStatic |
527529
super::BlockTailExpression(_) |
@@ -570,6 +572,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
570572
super::ReturnNoExpression |
571573
super::RepeatVec |
572574
super::FieldSized(_) |
575+
super::FieldDynSized |
573576
super::ConstSized |
574577
super::SharedStatic |
575578
super::BlockTailExpression(_) |

src/librustc/ty/maps/config.rs

+6
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::is_sized_raw<'tcx> {
6161
}
6262
}
6363

64+
impl<'tcx> QueryDescription<'tcx> for queries::is_dynsized_raw<'tcx> {
65+
fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String {
66+
format!("computing whether `{}` is `DynSized`", env.value)
67+
}
68+
}
69+
6470
impl<'tcx> QueryDescription<'tcx> for queries::is_freeze_raw<'tcx> {
6571
fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String {
6672
format!("computing whether `{}` is freeze", env.value)

src/librustc/ty/maps/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ define_maps! { <'tcx>
104104
[] fn adt_def: AdtDefOfItem(DefId) -> &'tcx ty::AdtDef,
105105
[] fn adt_destructor: AdtDestructor(DefId) -> Option<ty::Destructor>,
106106
[] fn adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>],
107+
[] fn adt_dynsized_constraint: DynSizedConstraint(DefId) -> &'tcx [Ty<'tcx>],
107108
[] fn adt_dtorck_constraint: DtorckConstraint(DefId) -> ty::DtorckConstraint<'tcx>,
108109

109110
/// True if this is a const fn
@@ -261,6 +262,7 @@ define_maps! { <'tcx>
261262
// `ty.is_copy()`, etc, since that will prune the environment where possible.
262263
[] fn is_copy_raw: is_copy_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
263264
[] fn is_sized_raw: is_sized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
265+
[] fn is_dynsized_raw: is_dynsized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
264266
[] fn is_freeze_raw: is_freeze_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
265267
[] fn needs_drop_raw: needs_drop_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
266268
[] 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
438440
DepConstructor::IsFreeze { param_env }
439441
}
440442

443+
fn is_dynsized_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> {
444+
DepConstructor::IsDynSized { param_env }
445+
}
446+
441447
fn needs_drop_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> {
442448
DepConstructor::NeedsDrop { param_env }
443449
}

0 commit comments

Comments
 (0)