Skip to content

Commit c0cf410

Browse files
committed
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<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 da549e1 commit c0cf410

File tree

26 files changed

+452
-107
lines changed

26 files changed

+452
-107
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
#[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+
#[lang = "send"]
52+
#[cfg(stage0)]
4353
#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"]
4454
pub unsafe trait Send {
4555
// empty.
@@ -49,9 +59,9 @@ pub unsafe trait Send {
4959
unsafe impl Send for .. { }
5060

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

5666
/// Types with a constant size known at compile time.
5767
///
@@ -94,6 +104,29 @@ pub trait Sized {
94104
// Empty.
95105
}
96106

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

354397
#[stable(feature = "rust1", since = "1.0.0")]
355-
impl<T: ?Sized> !Sync for *const T { }
398+
impl<T: ?DynSized> !Sync for *const T { }
356399
#[stable(feature = "rust1", since = "1.0.0")]
357-
impl<T: ?Sized> !Sync for *mut T { }
400+
impl<T: ?DynSized> !Sync for *mut T { }
358401

359402
macro_rules! impls{
360403
($t: ident) => (
361404
#[stable(feature = "rust1", since = "1.0.0")]
362-
impl<T:?Sized> Hash for $t<T> {
405+
impl<T:?DynSized> Hash for $t<T> {
363406
#[inline]
364407
fn hash<H: Hasher>(&self, _: &mut H) {
365408
}
366409
}
367410

368411
#[stable(feature = "rust1", since = "1.0.0")]
369-
impl<T:?Sized> cmp::PartialEq for $t<T> {
412+
impl<T:?DynSized> cmp::PartialEq for $t<T> {
370413
fn eq(&self, _other: &$t<T>) -> bool {
371414
true
372415
}
373416
}
374417

375418
#[stable(feature = "rust1", since = "1.0.0")]
376-
impl<T:?Sized> cmp::Eq for $t<T> {
419+
impl<T:?DynSized> cmp::Eq for $t<T> {
377420
}
378421

379422
#[stable(feature = "rust1", since = "1.0.0")]
380-
impl<T:?Sized> cmp::PartialOrd for $t<T> {
423+
impl<T:?DynSized> cmp::PartialOrd for $t<T> {
381424
fn partial_cmp(&self, _other: &$t<T>) -> Option<cmp::Ordering> {
382425
Option::Some(cmp::Ordering::Equal)
383426
}
384427
}
385428

386429
#[stable(feature = "rust1", since = "1.0.0")]
387-
impl<T:?Sized> cmp::Ord for $t<T> {
430+
impl<T:?DynSized> cmp::Ord for $t<T> {
388431
fn cmp(&self, _other: &$t<T>) -> cmp::Ordering {
389432
cmp::Ordering::Equal
390433
}
391434
}
392435

393436
#[stable(feature = "rust1", since = "1.0.0")]
394-
impl<T:?Sized> Copy for $t<T> { }
437+
impl<T:?DynSized> Copy for $t<T> { }
395438

396439
#[stable(feature = "rust1", since = "1.0.0")]
397-
impl<T:?Sized> Clone for $t<T> {
440+
impl<T:?DynSized> Clone for $t<T> {
398441
fn clone(&self) -> $t<T> {
399442
$t
400443
}
401444
}
402445

403446
#[stable(feature = "rust1", since = "1.0.0")]
404-
impl<T:?Sized> Default for $t<T> {
447+
impl<T:?DynSized> Default for $t<T> {
405448
fn default() -> $t<T> {
406449
$t
407450
}
@@ -544,29 +587,33 @@ macro_rules! impls{
544587
/// [drop check]: ../../nomicon/dropck.html
545588
#[lang = "phantom_data"]
546589
#[stable(feature = "rust1", since = "1.0.0")]
547-
pub struct PhantomData<T:?Sized>;
590+
pub struct PhantomData<T:?DynSized>;
548591

549592
impls! { PhantomData }
550593

551-
mod impls {
552-
#[stable(feature = "rust1", since = "1.0.0")]
553-
unsafe impl<'a, T: Sync + ?Sized> Send for &'a T {}
554-
#[stable(feature = "rust1", since = "1.0.0")]
555-
unsafe impl<'a, T: Send + ?Sized> Send for &'a mut T {}
556-
}
594+
#[stable(feature = "rust1", since = "1.0.0")]
595+
unsafe impl<'a, T: Sync + ?DynSized> Send for &'a T {}
596+
#[stable(feature = "rust1", since = "1.0.0")]
597+
unsafe impl<'a, T: Send + ?DynSized> Send for &'a mut T {}
557598

558599
/// Compiler-internal trait used to determine whether a type contains
559600
/// any `UnsafeCell` internally, but not through an indirection.
560601
/// This affects, for example, whether a `static` of that type is
561602
/// placed in read-only static memory or writable static memory.
562603
#[lang = "freeze"]
604+
#[cfg(not(stage0))]
605+
unsafe trait Freeze: ?DynSized {}
606+
607+
/// docs
608+
#[lang = "freeze"]
609+
#[cfg(stage0)]
563610
unsafe trait Freeze {}
564611

565612
unsafe impl Freeze for .. {}
566613

567-
impl<T: ?Sized> !Freeze for UnsafeCell<T> {}
568-
unsafe impl<T: ?Sized> Freeze for PhantomData<T> {}
569-
unsafe impl<T: ?Sized> Freeze for *const T {}
570-
unsafe impl<T: ?Sized> Freeze for *mut T {}
571-
unsafe impl<'a, T: ?Sized> Freeze for &'a T {}
572-
unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {}
614+
impl<T: ?DynSized> !Freeze for UnsafeCell<T> {}
615+
unsafe impl<T: ?DynSized> Freeze for PhantomData<T> {}
616+
unsafe impl<T: ?DynSized> Freeze for *const T {}
617+
unsafe impl<T: ?DynSized> Freeze for *mut T {}
618+
unsafe impl<'a, T: ?DynSized> Freeze for &'a T {}
619+
unsafe impl<'a, T: ?DynSized> Freeze for &'a mut T {}

src/libcore/ptr.rs

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

src/librustc/dep_graph/dep_node.rs

+2
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,7 @@ define_dep_nodes!( <'tcx>
477477
[] IsForeignItem(DefId),
478478
[] TypeParamPredicates { item_id: DefId, param_id: DefId },
479479
[] SizedConstraint(DefId),
480+
[] DynSizedConstraint(DefId),
480481
[] DtorckConstraint(DefId),
481482
[] AdtDestructor(DefId),
482483
[] AssociatedItemDefIds(DefId),
@@ -492,6 +493,7 @@ define_dep_nodes!( <'tcx>
492493

493494
[anon] IsCopy,
494495
[anon] IsSized,
496+
[anon] IsDynSized,
495497
[anon] IsFreeze,
496498
[anon] NeedsDrop,
497499
[anon] Layout,

src/librustc/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
#![cfg_attr(stage0, feature(const_fn))]
6060
#![cfg_attr(not(stage0), feature(const_atomic_bool_new))]
6161

62-
#![recursion_limit="256"]
62+
#![recursion_limit="512"]
6363

6464
extern crate arena;
6565
#[macro_use] extern crate bitflags;

src/librustc/middle/lang_items.rs

+1
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ language_item_table! {
230230

231231
SendTraitLangItem, "send", send_trait;
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
@@ -1125,6 +1125,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
11251125
ObligationCauseCode::StructInitializerSized => {
11261126
err.note("structs must have a statically known size to be initialized");
11271127
}
1128+
ObligationCauseCode::FieldDynSized => {
1129+
err.note("the last field of a struct or tuple must have a dynamically sized type");
1130+
}
11281131
ObligationCauseCode::FieldSized(ref item) => {
11291132
match *item {
11301133
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 {
@@ -2056,6 +2062,53 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
20562062
}
20572063
}
20582064

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

src/librustc/traits/structural_impls.rs

+3
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
211211
super::SizedReturnType => Some(super::SizedReturnType),
212212
super::RepeatVec => Some(super::RepeatVec),
213213
super::FieldSized(item) => Some(super::FieldSized(item)),
214+
super::FieldDynSized => Some(super::FieldDynSized),
214215
super::ConstSized => Some(super::ConstSized),
215216
super::SharedStatic => Some(super::SharedStatic),
216217
super::BuiltinDerivedObligation(ref cause) => {
@@ -531,6 +532,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
531532
super::ReturnNoExpression |
532533
super::RepeatVec |
533534
super::FieldSized(_) |
535+
super::FieldDynSized |
534536
super::ConstSized |
535537
super::SharedStatic |
536538
super::BlockTailExpression(_) |
@@ -579,6 +581,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
579581
super::ReturnNoExpression |
580582
super::RepeatVec |
581583
super::FieldSized(_) |
584+
super::FieldDynSized |
582585
super::ConstSized |
583586
super::SharedStatic |
584587
super::BlockTailExpression(_) |

src/librustc/ty/maps/config.rs

+6
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ impl<'tcx> QueryDescription for queries::is_sized_raw<'tcx> {
4545
}
4646
}
4747

48+
impl<'tcx> QueryDescription for queries::is_dynsized_raw<'tcx> {
49+
fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String {
50+
format!("computing whether `{}` is `DynSized`", env.value)
51+
}
52+
}
53+
4854
impl<'tcx> QueryDescription for queries::is_freeze_raw<'tcx> {
4955
fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String {
5056
format!("computing whether `{}` is freeze", env.value)

src/librustc/ty/maps/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ define_maps! { <'tcx>
100100
[] fn adt_def: AdtDefOfItem(DefId) -> &'tcx ty::AdtDef,
101101
[] fn adt_destructor: AdtDestructor(DefId) -> Option<ty::Destructor>,
102102
[] fn adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>],
103+
[] fn adt_dynsized_constraint: DynSizedConstraint(DefId) -> &'tcx [Ty<'tcx>],
103104
[] fn adt_dtorck_constraint: DtorckConstraint(DefId) -> ty::DtorckConstraint<'tcx>,
104105

105106
/// True if this is a const fn
@@ -244,6 +245,7 @@ define_maps! { <'tcx>
244245
// `ty.is_copy()`, etc, since that will prune the environment where possible.
245246
[] fn is_copy_raw: is_copy_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
246247
[] fn is_sized_raw: is_sized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
248+
[] fn is_dynsized_raw: is_dynsized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
247249
[] fn is_freeze_raw: is_freeze_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
248250
[] fn needs_drop_raw: needs_drop_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
249251
[] fn layout_raw: layout_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
@@ -398,6 +400,10 @@ fn is_sized_dep_node<'tcx>(_: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor
398400
DepConstructor::IsSized
399401
}
400402

403+
fn is_dynsized_dep_node<'tcx>(_: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> {
404+
DepConstructor::IsDynSized
405+
}
406+
401407
fn is_freeze_dep_node<'tcx>(_: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> {
402408
DepConstructor::IsFreeze
403409
}

0 commit comments

Comments
 (0)