Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 373fcd1

Browse files
authoredOct 19, 2016
Rollup merge of rust-lang#37117 - pnkfelix:may-dangle-attr, r=nikomatsakis
`#[may_dangle]` attribute `#[may_dangle]` attribute Second step of rust-lang#34761. Last big hurdle before we can work in earnest towards Allocator integration (rust-lang#32838) Note: I am not clear if this is *also* a syntax-breaking change that needs to be part of a breaking-batch.
2 parents 6e3a72d + 10a58ac commit 373fcd1

27 files changed

+1098
-36
lines changed
 

‎src/librustc/hir/lowering.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ impl<'a> LoweringContext<'a> {
401401
bounds: self.lower_bounds(&tp.bounds),
402402
default: tp.default.as_ref().map(|x| self.lower_ty(x)),
403403
span: tp.span,
404+
pure_wrt_drop: tp.attrs.iter().any(|attr| attr.check_name("may_dangle")),
404405
}
405406
}
406407

@@ -420,6 +421,7 @@ impl<'a> LoweringContext<'a> {
420421
hir::LifetimeDef {
421422
lifetime: self.lower_lifetime(&l.lifetime),
422423
bounds: self.lower_lifetimes(&l.bounds),
424+
pure_wrt_drop: l.attrs.iter().any(|attr| attr.check_name("may_dangle")),
423425
}
424426
}
425427

‎src/librustc/hir/mod.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ impl fmt::Debug for Lifetime {
9595
pub struct LifetimeDef {
9696
pub lifetime: Lifetime,
9797
pub bounds: HirVec<Lifetime>,
98+
pub pure_wrt_drop: bool,
9899
}
99100

100101
/// A "Path" is essentially Rust's notion of a name; for instance:
@@ -290,6 +291,7 @@ pub struct TyParam {
290291
pub bounds: TyParamBounds,
291292
pub default: Option<P<Ty>>,
292293
pub span: Span,
294+
pub pure_wrt_drop: bool,
293295
}
294296

295297
/// Represents lifetimes and type parameters attached to a declaration
@@ -328,6 +330,36 @@ impl Generics {
328330
}
329331
}
330332

333+
pub enum UnsafeGeneric {
334+
Region(LifetimeDef, &'static str),
335+
Type(TyParam, &'static str),
336+
}
337+
338+
impl UnsafeGeneric {
339+
pub fn attr_name(&self) -> &'static str {
340+
match *self {
341+
UnsafeGeneric::Region(_, s) => s,
342+
UnsafeGeneric::Type(_, s) => s,
343+
}
344+
}
345+
}
346+
347+
impl Generics {
348+
pub fn carries_unsafe_attr(&self) -> Option<UnsafeGeneric> {
349+
for r in &self.lifetimes {
350+
if r.pure_wrt_drop {
351+
return Some(UnsafeGeneric::Region(r.clone(), "may_dangle"));
352+
}
353+
}
354+
for t in &self.ty_params {
355+
if t.pure_wrt_drop {
356+
return Some(UnsafeGeneric::Type(t.clone(), "may_dangle"));
357+
}
358+
}
359+
return None;
360+
}
361+
}
362+
331363
/// A `where` clause in a definition
332364
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
333365
pub struct WhereClause {

‎src/librustc/infer/error_reporting.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,16 +1231,17 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
12311231
lifetime: hir::Lifetime,
12321232
region_names: &HashSet<ast::Name>)
12331233
-> hir::HirVec<hir::TyParam> {
1234-
ty_params.iter().map(|ty_param| {
1235-
let bounds = self.rebuild_ty_param_bounds(ty_param.bounds.clone(),
1234+
ty_params.into_iter().map(|ty_param| {
1235+
let bounds = self.rebuild_ty_param_bounds(ty_param.bounds,
12361236
lifetime,
12371237
region_names);
12381238
hir::TyParam {
12391239
name: ty_param.name,
12401240
id: ty_param.id,
12411241
bounds: bounds,
1242-
default: ty_param.default.clone(),
1242+
default: ty_param.default,
12431243
span: ty_param.span,
1244+
pure_wrt_drop: ty_param.pure_wrt_drop,
12441245
}
12451246
}).collect()
12461247
}
@@ -1299,8 +1300,11 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
12991300
-> hir::Generics {
13001301
let mut lifetimes = Vec::new();
13011302
for lt in add {
1302-
lifetimes.push(hir::LifetimeDef { lifetime: *lt,
1303-
bounds: hir::HirVec::new() });
1303+
lifetimes.push(hir::LifetimeDef {
1304+
lifetime: *lt,
1305+
bounds: hir::HirVec::new(),
1306+
pure_wrt_drop: false,
1307+
});
13041308
}
13051309
for lt in &generics.lifetimes {
13061310
if keep.contains(&lt.lifetime.name) ||

‎src/librustc/ty/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,11 @@ pub struct TypeParameterDef<'tcx> {
680680
pub default_def_id: DefId, // for use in error reporing about defaults
681681
pub default: Option<Ty<'tcx>>,
682682
pub object_lifetime_default: ObjectLifetimeDefault<'tcx>,
683+
684+
/// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute
685+
/// on generic parameter `T`, asserts data behind the parameter
686+
/// `T` won't be accessed during the parent type's `Drop` impl.
687+
pub pure_wrt_drop: bool,
683688
}
684689

685690
#[derive(Clone, RustcEncodable, RustcDecodable)]
@@ -688,6 +693,11 @@ pub struct RegionParameterDef<'tcx> {
688693
pub def_id: DefId,
689694
pub index: u32,
690695
pub bounds: Vec<&'tcx ty::Region>,
696+
697+
/// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute
698+
/// on generic parameter `'a`, asserts data of lifetime `'a`
699+
/// won't be accessed during the parent type's `Drop` impl.
700+
pub pure_wrt_drop: bool,
691701
}
692702

693703
impl<'tcx> RegionParameterDef<'tcx> {
@@ -732,6 +742,14 @@ impl<'tcx> Generics<'tcx> {
732742
pub fn count(&self) -> usize {
733743
self.parent_count() + self.own_count()
734744
}
745+
746+
pub fn region_param(&self, param: &EarlyBoundRegion) -> &RegionParameterDef<'tcx> {
747+
&self.regions[param.index as usize - self.has_self as usize]
748+
}
749+
750+
pub fn type_param(&self, param: &ParamTy) -> &TypeParameterDef<'tcx> {
751+
&self.types[param.idx as usize - self.has_self as usize - self.regions.len()]
752+
}
735753
}
736754

737755
/// Bounds on generics.

‎src/librustc/ty/structural_impls.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> {
716716
default: self.default.fold_with(folder),
717717
default_def_id: self.default_def_id,
718718
object_lifetime_default: self.object_lifetime_default.fold_with(folder),
719+
pure_wrt_drop: self.pure_wrt_drop,
719720
}
720721
}
721722

@@ -754,6 +755,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef<'tcx> {
754755
def_id: self.def_id,
755756
index: self.index,
756757
bounds: self.bounds.fold_with(folder),
758+
pure_wrt_drop: self.pure_wrt_drop,
757759
}
758760
}
759761

‎src/librustc_typeck/check/dropck.rs

Lines changed: 157 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
7171
ccx: &CrateCtxt<'a, 'tcx>,
7272
drop_impl_did: DefId,
7373
drop_impl_ty: Ty<'tcx>,
74-
self_type_did: DefId) -> Result<(), ()>
74+
self_type_did: DefId)
75+
-> Result<(), ()>
7576
{
7677
let tcx = ccx.tcx;
7778
let drop_impl_node_id = tcx.map.as_local_node_id(drop_impl_did).unwrap();
@@ -123,7 +124,9 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>(
123124
drop_impl_did: DefId,
124125
dtor_predicates: &ty::GenericPredicates<'tcx>,
125126
self_type_did: DefId,
126-
self_to_impl_substs: &Substs<'tcx>) -> Result<(), ()> {
127+
self_to_impl_substs: &Substs<'tcx>)
128+
-> Result<(), ()>
129+
{
127130

128131
// Here is an example, analogous to that from
129132
// `compare_impl_method`.
@@ -350,7 +353,8 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>(
350353
cx: &mut DropckContext<'a, 'b, 'gcx, 'tcx>,
351354
context: TypeContext,
352355
ty: Ty<'tcx>,
353-
depth: usize) -> Result<(), Error<'tcx>>
356+
depth: usize)
357+
-> Result<(), Error<'tcx>>
354358
{
355359
let tcx = cx.rcx.tcx;
356360
// Issue #22443: Watch out for overflow. While we are careful to
@@ -402,16 +406,27 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>(
402406
// unbounded type parameter `T`, we must resume the recursive
403407
// analysis on `T` (since it would be ignored by
404408
// type_must_outlive).
405-
if has_dtor_of_interest(tcx, ty) {
406-
debug!("iterate_over_potentially_unsafe_regions_in_type \
407-
{}ty: {} - is a dtorck type!",
408-
(0..depth).map(|_| ' ').collect::<String>(),
409-
ty);
410-
411-
cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span),
412-
ty, tcx.mk_region(ty::ReScope(cx.parent_scope)));
413-
414-
return Ok(());
409+
let dropck_kind = has_dtor_of_interest(tcx, ty);
410+
debug!("iterate_over_potentially_unsafe_regions_in_type \
411+
ty: {:?} dropck_kind: {:?}", ty, dropck_kind);
412+
match dropck_kind {
413+
DropckKind::NoBorrowedDataAccessedInMyDtor => {
414+
// The maximally blind attribute.
415+
}
416+
DropckKind::BorrowedDataMustStrictlyOutliveSelf => {
417+
cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span),
418+
ty, tcx.mk_region(ty::ReScope(cx.parent_scope)));
419+
return Ok(());
420+
}
421+
DropckKind::RevisedSelf(revised_ty) => {
422+
cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span),
423+
revised_ty, tcx.mk_region(ty::ReScope(cx.parent_scope)));
424+
// Do not return early from this case; we want
425+
// to recursively process the internal structure of Self
426+
// (because even though the Drop for Self has been asserted
427+
// safe, the types instantiated for the generics of Self
428+
// may themselves carry dropck constraints.)
429+
}
415430
}
416431

417432
debug!("iterate_over_potentially_unsafe_regions_in_type \
@@ -492,16 +507,140 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>(
492507
}
493508
}
494509

510+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
511+
enum DropckKind<'tcx> {
512+
/// The "safe" kind; i.e. conservatively assume any borrow
513+
/// accessed by dtor, and therefore such data must strictly
514+
/// outlive self.
515+
///
516+
/// Equivalent to RevisedTy with no change to the self type.
517+
BorrowedDataMustStrictlyOutliveSelf,
518+
519+
/// The nearly completely-unsafe kind.
520+
///
521+
/// Equivalent to RevisedSelf with *all* parameters remapped to ()
522+
/// (maybe...?)
523+
NoBorrowedDataAccessedInMyDtor,
524+
525+
/// Assume all borrowed data access by dtor occurs as if Self has the
526+
/// type carried by this variant. In practice this means that some
527+
/// of the type parameters are remapped to `()` (and some lifetime
528+
/// parameters remapped to `'static`), because the developer has asserted
529+
/// that the destructor will not access their contents.
530+
RevisedSelf(Ty<'tcx>),
531+
}
532+
533+
/// Returns the classification of what kind of check should be applied
534+
/// to `ty`, which may include a revised type where some of the type
535+
/// parameters are re-mapped to `()` to reflect the destructor's
536+
/// "purity" with respect to their actual contents.
495537
fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
496-
ty: Ty<'tcx>) -> bool {
538+
ty: Ty<'tcx>)
539+
-> DropckKind<'tcx> {
497540
match ty.sty {
498-
ty::TyAdt(def, _) => {
499-
def.is_dtorck(tcx)
541+
ty::TyAdt(adt_def, substs) => {
542+
if !adt_def.is_dtorck(tcx) {
543+
return DropckKind::NoBorrowedDataAccessedInMyDtor;
544+
}
545+
546+
// Find the `impl<..> Drop for _` to inspect any
547+
// attributes attached to the impl's generics.
548+
let dtor_method = adt_def.destructor()
549+
.expect("dtorck type without destructor impossible");
550+
let method = tcx.impl_or_trait_item(dtor_method);
551+
let impl_id: DefId = method.container().id();
552+
let revised_ty = revise_self_ty(tcx, adt_def, impl_id, substs);
553+
return DropckKind::RevisedSelf(revised_ty);
500554
}
501555
ty::TyTrait(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
502556
debug!("ty: {:?} isn't known, and therefore is a dropck type", ty);
503-
true
557+
return DropckKind::BorrowedDataMustStrictlyOutliveSelf;
504558
},
505-
_ => false
559+
_ => {
560+
return DropckKind::NoBorrowedDataAccessedInMyDtor;
561+
}
506562
}
507563
}
564+
565+
// Constructs new Ty just like the type defined by `adt_def` coupled
566+
// with `substs`, except each type and lifetime parameter marked as
567+
// `#[may_dangle]` in the Drop impl (identified by `impl_id`) is
568+
// respectively mapped to `()` or `'static`.
569+
//
570+
// For example: If the `adt_def` maps to:
571+
//
572+
// enum Foo<'a, X, Y> { ... }
573+
//
574+
// and the `impl_id` maps to:
575+
//
576+
// impl<#[may_dangle] 'a, X, #[may_dangle] Y> Drop for Foo<'a, X, Y> { ... }
577+
//
578+
// then revises input: `Foo<'r,i64,&'r i64>` to: `Foo<'static,i64,()>`
579+
fn revise_self_ty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
580+
adt_def: ty::AdtDef<'tcx>,
581+
impl_id: DefId,
582+
substs: &Substs<'tcx>)
583+
-> Ty<'tcx> {
584+
// Get generics for `impl Drop` to query for `#[may_dangle]` attr.
585+
let impl_bindings = tcx.lookup_generics(impl_id);
586+
587+
// Get Substs attached to Self on `impl Drop`; process in parallel
588+
// with `substs`, replacing dangling entries as appropriate.
589+
let self_substs = {
590+
let impl_self_ty: Ty<'tcx> = tcx.lookup_item_type(impl_id).ty;
591+
if let ty::TyAdt(self_adt_def, self_substs) = impl_self_ty.sty {
592+
assert_eq!(adt_def, self_adt_def);
593+
self_substs
594+
} else {
595+
bug!("Self in `impl Drop for _` must be an Adt.");
596+
}
597+
};
598+
599+
// Walk `substs` + `self_substs`, build new substs appropriate for
600+
// `adt_def`; each non-dangling param reuses entry from `substs`.
601+
//
602+
// Note: The manner we map from a right-hand side (i.e. Region or
603+
// Ty) for a given `def` to generic parameter associated with that
604+
// right-hand side is tightly coupled to `Drop` impl constraints.
605+
//
606+
// E.g. we know such a Ty must be `TyParam`, because a destructor
607+
// for `struct Foo<X>` is defined via `impl<Y> Drop for Foo<Y>`,
608+
// and never by (for example) `impl<Z> Drop for Foo<Vec<Z>>`.
609+
let substs = Substs::for_item(
610+
tcx,
611+
adt_def.did,
612+
|def, _| {
613+
let r_orig = substs.region_for_def(def);
614+
let impl_self_orig = self_substs.region_for_def(def);
615+
let r = if let ty::Region::ReEarlyBound(ref ebr) = *impl_self_orig {
616+
if impl_bindings.region_param(ebr).pure_wrt_drop {
617+
tcx.mk_region(ty::ReStatic)
618+
} else {
619+
r_orig
620+
}
621+
} else {
622+
bug!("substs for an impl must map regions to ReEarlyBound");
623+
};
624+
debug!("has_dtor_of_interest mapping def {:?} orig {:?} to {:?}",
625+
def, r_orig, r);
626+
r
627+
},
628+
|def, _| {
629+
let t_orig = substs.type_for_def(def);
630+
let impl_self_orig = self_substs.type_for_def(def);
631+
let t = if let ty::TypeVariants::TyParam(ref pt) = impl_self_orig.sty {
632+
if impl_bindings.type_param(pt).pure_wrt_drop {
633+
tcx.mk_nil()
634+
} else {
635+
t_orig
636+
}
637+
} else {
638+
bug!("substs for an impl must map types to TyParam");
639+
};
640+
debug!("has_dtor_of_interest mapping def {:?} orig {:?} {:?} to {:?} {:?}",
641+
def, t_orig, t_orig.sty, t, t.sty);
642+
t
643+
});
644+
645+
return tcx.mk_adt(adt_def, &substs);
646+
}

‎src/librustc_typeck/coherence/unsafety.rs

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
1414
use rustc::ty::TyCtxt;
1515
use rustc::hir::intravisit;
16-
use rustc::hir;
16+
use rustc::hir::{self, Unsafety};
1717

1818
pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
1919
let mut orphan = UnsafetyChecker { tcx: tcx };
@@ -27,6 +27,7 @@ struct UnsafetyChecker<'cx, 'tcx: 'cx> {
2727
impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
2828
fn check_unsafety_coherence(&mut self,
2929
item: &'v hir::Item,
30+
impl_generics: Option<&hir::Generics>,
3031
unsafety: hir::Unsafety,
3132
polarity: hir::ImplPolarity) {
3233
match self.tcx.impl_trait_ref(self.tcx.map.local_def_id(item.id)) {
@@ -47,33 +48,44 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
4748

4849
Some(trait_ref) => {
4950
let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id);
50-
match (trait_def.unsafety, unsafety, polarity) {
51-
(hir::Unsafety::Unsafe, hir::Unsafety::Unsafe, hir::ImplPolarity::Negative) => {
51+
let unsafe_attr = impl_generics.and_then(|g| g.carries_unsafe_attr());
52+
match (trait_def.unsafety, unsafe_attr, unsafety, polarity) {
53+
(_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative) => {
5254
span_err!(self.tcx.sess,
5355
item.span,
5456
E0198,
5557
"negative implementations are not unsafe");
5658
}
5759

58-
(hir::Unsafety::Normal, hir::Unsafety::Unsafe, _) => {
60+
(Unsafety::Normal, None, Unsafety::Unsafe, _) => {
5961
span_err!(self.tcx.sess,
6062
item.span,
6163
E0199,
6264
"implementing the trait `{}` is not unsafe",
6365
trait_ref);
6466
}
6567

66-
(hir::Unsafety::Unsafe, hir::Unsafety::Normal, hir::ImplPolarity::Positive) => {
68+
(Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => {
6769
span_err!(self.tcx.sess,
6870
item.span,
6971
E0200,
7072
"the trait `{}` requires an `unsafe impl` declaration",
7173
trait_ref);
7274
}
7375

74-
(hir::Unsafety::Unsafe, hir::Unsafety::Normal, hir::ImplPolarity::Negative) |
75-
(hir::Unsafety::Unsafe, hir::Unsafety::Unsafe, hir::ImplPolarity::Positive) |
76-
(hir::Unsafety::Normal, hir::Unsafety::Normal, _) => {
76+
(Unsafety::Normal, Some(g), Unsafety::Normal, hir::ImplPolarity::Positive) =>
77+
{
78+
span_err!(self.tcx.sess,
79+
item.span,
80+
E0569,
81+
"requires an `unsafe impl` declaration due to `#[{}]` attribute",
82+
g.attr_name());
83+
}
84+
85+
(_, _, Unsafety::Normal, hir::ImplPolarity::Negative) |
86+
(Unsafety::Unsafe, _, Unsafety::Unsafe, hir::ImplPolarity::Positive) |
87+
(Unsafety::Normal, Some(_), Unsafety::Unsafe, hir::ImplPolarity::Positive) |
88+
(Unsafety::Normal, None, Unsafety::Normal, _) => {
7789
// OK
7890
}
7991
}
@@ -86,10 +98,10 @@ impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
8698
fn visit_item(&mut self, item: &'v hir::Item) {
8799
match item.node {
88100
hir::ItemDefaultImpl(unsafety, _) => {
89-
self.check_unsafety_coherence(item, unsafety, hir::ImplPolarity::Positive);
101+
self.check_unsafety_coherence(item, None, unsafety, hir::ImplPolarity::Positive);
90102
}
91-
hir::ItemImpl(unsafety, polarity, ..) => {
92-
self.check_unsafety_coherence(item, unsafety, polarity);
103+
hir::ItemImpl(unsafety, polarity, ref generics, ..) => {
104+
self.check_unsafety_coherence(item, Some(generics), unsafety, polarity);
93105
}
94106
_ => {}
95107
}

‎src/librustc_typeck/collect.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1482,6 +1482,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
14821482
default_def_id: tcx.map.local_def_id(parent),
14831483
default: None,
14841484
object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault,
1485+
pure_wrt_drop: false,
14851486
};
14861487
tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone());
14871488
opt_self = Some(def);
@@ -1526,7 +1527,8 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
15261527
def_id: tcx.map.local_def_id(l.lifetime.id),
15271528
bounds: l.bounds.iter().map(|l| {
15281529
ast_region_to_region(tcx, l)
1529-
}).collect()
1530+
}).collect(),
1531+
pure_wrt_drop: l.pure_wrt_drop,
15301532
}
15311533
}).collect::<Vec<_>>();
15321534

@@ -1926,6 +1928,7 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
19261928
default_def_id: ccx.tcx.map.local_def_id(parent),
19271929
default: default,
19281930
object_lifetime_default: object_lifetime_default,
1931+
pure_wrt_drop: param.pure_wrt_drop,
19291932
};
19301933

19311934
if def.name == keywords::SelfType.name() {

‎src/librustc_typeck/diagnostics.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2819,6 +2819,26 @@ not a distinct static type. Likewise, it's not legal to attempt to
28192819
behavior for specific enum variants.
28202820
"##,
28212821

2822+
E0569: r##"
2823+
If an impl has a generic parameter with the `#[may_dangle]` attribute, then
2824+
that impl must be declared as an `unsafe impl. For example:
2825+
2826+
```compile_fail,E0569
2827+
#![feature(generic_param_attrs)]
2828+
#![feature(dropck_eyepatch)]
2829+
2830+
struct Foo<X>(X);
2831+
impl<#[may_dangle] X> Drop for Foo<X> {
2832+
fn drop(&mut self) { }
2833+
}
2834+
```
2835+
2836+
In this example, we are asserting that the destructor for `Foo` will not
2837+
access any data of type `X`, and require this assertion to be true for
2838+
overall safety in our program. The compiler does not currently attempt to
2839+
verify this assertion; therefore we must tag this `impl` as unsafe.
2840+
"##,
2841+
28222842
E0318: r##"
28232843
Default impls for a trait must be located in the same crate where the trait was
28242844
defined. For more information see the [opt-in builtin traits RFC](https://github

‎src/libsyntax/feature_gate.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,9 @@ declare_features! (
167167
// RFC 1238
168168
(active, dropck_parametricity, "1.3.0", Some(28498)),
169169

170+
// Allows using the may_dangle attribute; RFC 1327
171+
(active, dropck_eyepatch, "1.10.0", Some(34761)),
172+
170173
// Allows the use of custom attributes; RFC 572
171174
(active, custom_attribute, "1.0.0", Some(29642)),
172175

@@ -616,6 +619,11 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat
616619
"unsafe_destructor_blind_to_params has unstable semantics \
617620
and may be removed in the future",
618621
cfg_fn!(dropck_parametricity))),
622+
("may_dangle",
623+
Normal,
624+
Gated("dropck_eyepatch",
625+
"may_dangle has unstable semantics and may be removed in the future",
626+
cfg_fn!(dropck_eyepatch))),
619627
("unwind", Whitelisted, Gated("unwind_attributes", "#[unwind] is experimental",
620628
cfg_fn!(unwind_attributes))),
621629

‎src/libsyntax/print/pprust.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,6 +1361,7 @@ impl<'a> State<'a> {
13611361
if comma {
13621362
try!(self.word_space(","))
13631363
}
1364+
try!(self.print_outer_attributes_inline(&lifetime_def.attrs));
13641365
try!(self.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds));
13651366
comma = true;
13661367
}
@@ -2803,6 +2804,7 @@ impl<'a> State<'a> {
28032804
try!(self.commasep(Inconsistent, &ints[..], |s, &idx| {
28042805
if idx < generics.lifetimes.len() {
28052806
let lifetime_def = &generics.lifetimes[idx];
2807+
try!(s.print_outer_attributes_inline(&lifetime_def.attrs));
28062808
s.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds)
28072809
} else {
28082810
let idx = idx - generics.lifetimes.len();
@@ -2816,6 +2818,7 @@ impl<'a> State<'a> {
28162818
}
28172819

28182820
pub fn print_ty_param(&mut self, param: &ast::TyParam) -> io::Result<()> {
2821+
try!(self.print_outer_attributes_inline(&param.attrs));
28192822
try!(self.print_ident(param.ident));
28202823
try!(self.print_bounds(":", &param.bounds));
28212824
match param.default {

‎src/test/compile-fail/E0198.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(optin_builtin_traits)]
12+
13+
struct Foo;
14+
15+
unsafe impl !Clone for Foo { } //~ ERROR negative implementations are not unsafe [E0198]
16+
17+
fn main() {
18+
}

‎src/test/compile-fail/E0199.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212

1313
struct Foo;
1414

15-
unsafe impl !Clone for Foo { } //~ ERROR E0199
15+
trait Bar { }
16+
unsafe impl Bar for Foo { } //~ ERROR implementing the trait `Bar` is not unsafe [E0199]
1617

1718
fn main() {
1819
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Check that `may_dangle` is rejected if `dropck_eyepatch` feature gate is absent.
12+
13+
#![feature(generic_param_attrs)]
14+
15+
struct Pt<A>(A);
16+
impl<#[may_dangle] A> Drop for Pt<A> {
17+
//~^ ERROR may_dangle has unstable semantics and may be removed in the future
18+
//~| HELP add #![feature(dropck_eyepatch)] to the crate attributes to enable
19+
fn drop(&mut self) { }
20+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(generic_param_attrs)]
12+
#![feature(dropck_eyepatch)]
13+
14+
// The point of this test is to illustrate that the `#[may_dangle]`
15+
// attribute specifically allows, in the context of a type
16+
// implementing `Drop`, a generic parameter to be instantiated with a
17+
// lifetime that does not strictly outlive the owning type itself,
18+
// and that this attributes effects are preserved when importing
19+
// the type from another crate.
20+
//
21+
// See also dropck-eyepatch.rs for more information about the general
22+
// structure of the test.
23+
24+
use std::cell::RefCell;
25+
26+
pub trait Foo { fn foo(&self, _: &str); }
27+
28+
pub struct Dt<A: Foo>(pub &'static str, pub A);
29+
pub struct Dr<'a, B:'a+Foo>(pub &'static str, pub &'a B);
30+
pub struct Pt<A,B: Foo>(pub &'static str, pub A, pub B);
31+
pub struct Pr<'a, 'b, B:'a+'b+Foo>(pub &'static str, pub &'a B, pub &'b B);
32+
pub struct St<A: Foo>(pub &'static str, pub A);
33+
pub struct Sr<'a, B:'a+Foo>(pub &'static str, pub &'a B);
34+
35+
impl<A: Foo> Drop for Dt<A> {
36+
fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); }
37+
}
38+
impl<'a, B: Foo> Drop for Dr<'a, B> {
39+
fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); }
40+
}
41+
unsafe impl<#[may_dangle] A, B: Foo> Drop for Pt<A, B> {
42+
// (unsafe to access self.1 due to #[may_dangle] on A)
43+
fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); }
44+
}
45+
unsafe impl<#[may_dangle] 'a, 'b, B: Foo> Drop for Pr<'a, 'b, B> {
46+
// (unsafe to access self.1 due to #[may_dangle] on 'a)
47+
fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); }
48+
}
49+
50+
impl Foo for RefCell<String> {
51+
fn foo(&self, s: &str) {
52+
let s2 = format!("{}|{}", *self.borrow(), s);
53+
*self.borrow_mut() = s2;
54+
}
55+
}
56+
57+
impl<'a, T:Foo> Foo for &'a T {
58+
fn foo(&self, s: &str) {
59+
(*self).foo(s);
60+
}
61+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// aux-build:dropck_eyepatch_extern_crate.rs
12+
13+
extern crate dropck_eyepatch_extern_crate as other;
14+
15+
use other::{Dt,Dr,Pt,Pr,St,Sr};
16+
17+
fn main() {
18+
use std::cell::RefCell;
19+
20+
struct CheckOnDrop(RefCell<String>, &'static str);
21+
impl Drop for CheckOnDrop {
22+
fn drop(&mut self) { assert_eq!(*self.0.borrow(), self.1); }
23+
}
24+
25+
let c_long;
26+
let (c, dt, dr, pt, pr, st, sr)
27+
: (CheckOnDrop, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>);
28+
c_long = CheckOnDrop(RefCell::new("c_long".to_string()),
29+
"c_long|pr|pt|dr|dt");
30+
c = CheckOnDrop(RefCell::new("c".to_string()),
31+
"c");
32+
33+
// No error: sufficiently long-lived state can be referenced in dtors
34+
dt = Dt("dt", &c_long.0);
35+
dr = Dr("dr", &c_long.0);
36+
37+
// No error: Drop impl asserts .1 (A and &'a _) are not accessed
38+
pt = Pt("pt", &c.0, &c_long.0);
39+
pr = Pr("pr", &c.0, &c_long.0);
40+
41+
// No error: St and Sr have no destructor.
42+
st = St("st", &c.0);
43+
sr = Sr("sr", &c.0);
44+
45+
println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0));
46+
assert_eq!(*c_long.0.borrow(), "c_long");
47+
assert_eq!(*c.0.borrow(), "c");
48+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(generic_param_attrs)]
12+
#![feature(dropck_eyepatch)]
13+
14+
// The point of this test is to test uses of `#[may_dangle]` attribute
15+
// where the formal declaration order (in the impl generics) does not
16+
// match the actual usage order (in the type instantiation).
17+
//
18+
// See also dropck-eyepatch.rs for more information about the general
19+
// structure of the test.
20+
21+
trait Foo { fn foo(&self, _: &str); }
22+
23+
struct Dt<A: Foo>(&'static str, A);
24+
struct Dr<'a, B:'a+Foo>(&'static str, &'a B);
25+
struct Pt<A: Foo, B: Foo>(&'static str, A, B);
26+
struct Pr<'a, 'b, B:'a+'b+Foo>(&'static str, &'a B, &'b B);
27+
struct St<A: Foo>(&'static str, A);
28+
struct Sr<'a, B:'a+Foo>(&'static str, &'a B);
29+
30+
impl<A: Foo> Drop for Dt<A> {
31+
fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); }
32+
}
33+
impl<'a, B: Foo> Drop for Dr<'a, B> {
34+
fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); }
35+
}
36+
unsafe impl<B: Foo, #[may_dangle] A: Foo> Drop for Pt<A, B> {
37+
// (unsafe to access self.1 due to #[may_dangle] on A)
38+
fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); }
39+
}
40+
unsafe impl<'b, #[may_dangle] 'a, B: Foo> Drop for Pr<'a, 'b, B> {
41+
// (unsafe to access self.1 due to #[may_dangle] on 'a)
42+
fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); }
43+
}
44+
45+
fn main() {
46+
use std::cell::RefCell;
47+
48+
impl Foo for RefCell<String> {
49+
fn foo(&self, s: &str) {
50+
let s2 = format!("{}|{}", *self.borrow(), s);
51+
*self.borrow_mut() = s2;
52+
}
53+
}
54+
55+
impl<'a, T:Foo> Foo for &'a T {
56+
fn foo(&self, s: &str) {
57+
(*self).foo(s);
58+
}
59+
}
60+
61+
struct CheckOnDrop(RefCell<String>, &'static str);
62+
impl Drop for CheckOnDrop {
63+
fn drop(&mut self) { assert_eq!(*self.0.borrow(), self.1); }
64+
}
65+
66+
let c_long;
67+
let (c, dt, dr, pt, pr, st, sr)
68+
: (CheckOnDrop, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>);
69+
c_long = CheckOnDrop(RefCell::new("c_long".to_string()),
70+
"c_long|pr|pt|dr|dt");
71+
c = CheckOnDrop(RefCell::new("c".to_string()),
72+
"c");
73+
74+
// No error: sufficiently long-lived state can be referenced in dtors
75+
dt = Dt("dt", &c_long.0);
76+
dr = Dr("dr", &c_long.0);
77+
78+
// No error: Drop impl asserts .1 (A and &'a _) are not accessed
79+
pt = Pt("pt", &c.0, &c_long.0);
80+
pr = Pr("pr", &c.0, &c_long.0);
81+
82+
// No error: St and Sr have no destructor.
83+
st = St("st", &c.0);
84+
sr = Sr("sr", &c.0);
85+
86+
println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0));
87+
assert_eq!(*c_long.0.borrow(), "c_long");
88+
assert_eq!(*c.0.borrow(), "c");
89+
}

‎src/test/run-pass/dropck-eyepatch.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(generic_param_attrs)]
12+
#![feature(dropck_eyepatch)]
13+
14+
// The point of this test is to illustrate that the `#[may_dangle]`
15+
// attribute specifically allows, in the context of a type
16+
// implementing `Drop`, a generic parameter to be instantiated with a
17+
// lifetime that does not strictly outlive the owning type itself.
18+
//
19+
// Here we test that a model use of `#[may_dangle]` will compile and run.
20+
//
21+
// The illustration is made concrete by comparison with two variations
22+
// on the type with `#[may_dangle]`:
23+
//
24+
// 1. an analogous type that does not implement `Drop` (and thus
25+
// should exhibit maximal flexibility with respect to dropck), and
26+
//
27+
// 2. an analogous type that does not use `#[may_dangle]` (and thus
28+
// should exhibit the standard limitations imposed by dropck.
29+
//
30+
// The types in this file follow a pattern, {D,P,S}{t,r}, where:
31+
//
32+
// - D means "I implement Drop"
33+
//
34+
// - P means "I implement Drop but guarantee my (first) parameter is
35+
// pure, i.e. not accessed from the destructor"; no other parameters
36+
// are pure.
37+
//
38+
// - S means "I do not implement Drop"
39+
//
40+
// - t suffix is used when the first generic is a type
41+
//
42+
// - r suffix is used when the first generic is a lifetime.
43+
44+
trait Foo { fn foo(&self, _: &str); }
45+
46+
struct Dt<A: Foo>(&'static str, A);
47+
struct Dr<'a, B:'a+Foo>(&'static str, &'a B);
48+
struct Pt<A,B: Foo>(&'static str, A, B);
49+
struct Pr<'a, 'b, B:'a+'b+Foo>(&'static str, &'a B, &'b B);
50+
struct St<A: Foo>(&'static str, A);
51+
struct Sr<'a, B:'a+Foo>(&'static str, &'a B);
52+
53+
impl<A: Foo> Drop for Dt<A> {
54+
fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); }
55+
}
56+
impl<'a, B: Foo> Drop for Dr<'a, B> {
57+
fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); }
58+
}
59+
unsafe impl<#[may_dangle] A, B: Foo> Drop for Pt<A, B> {
60+
// (unsafe to access self.1 due to #[may_dangle] on A)
61+
fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); }
62+
}
63+
unsafe impl<#[may_dangle] 'a, 'b, B: Foo> Drop for Pr<'a, 'b, B> {
64+
// (unsafe to access self.1 due to #[may_dangle] on 'a)
65+
fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); }
66+
}
67+
68+
fn main() {
69+
use std::cell::RefCell;
70+
71+
impl Foo for RefCell<String> {
72+
fn foo(&self, s: &str) {
73+
let s2 = format!("{}|{}", *self.borrow(), s);
74+
*self.borrow_mut() = s2;
75+
}
76+
}
77+
78+
impl<'a, T:Foo> Foo for &'a T {
79+
fn foo(&self, s: &str) {
80+
(*self).foo(s);
81+
}
82+
}
83+
84+
struct CheckOnDrop(RefCell<String>, &'static str);
85+
impl Drop for CheckOnDrop {
86+
fn drop(&mut self) { assert_eq!(*self.0.borrow(), self.1); }
87+
}
88+
89+
let c_long;
90+
let (c, dt, dr, pt, pr, st, sr)
91+
: (CheckOnDrop, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>);
92+
c_long = CheckOnDrop(RefCell::new("c_long".to_string()),
93+
"c_long|pr|pt|dr|dt");
94+
c = CheckOnDrop(RefCell::new("c".to_string()),
95+
"c");
96+
97+
// No error: sufficiently long-lived state can be referenced in dtors
98+
dt = Dt("dt", &c_long.0);
99+
dr = Dr("dr", &c_long.0);
100+
101+
// No error: Drop impl asserts .1 (A and &'a _) are not accessed
102+
pt = Pt("pt", &c.0, &c_long.0);
103+
pr = Pr("pr", &c.0, &c_long.0);
104+
105+
// No error: St and Sr have no destructor.
106+
st = St("st", &c.0);
107+
sr = Sr("sr", &c.0);
108+
109+
println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0));
110+
assert_eq!(*c_long.0.borrow(), "c_long");
111+
assert_eq!(*c.0.borrow(), "c");
112+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(generic_param_attrs)]
12+
#![feature(dropck_eyepatch)]
13+
14+
// This is a support file for ../dropck-eyepatch-extern-crate.rs
15+
//
16+
// The point of this test is to illustrate that the `#[may_dangle]`
17+
// attribute specifically allows, in the context of a type
18+
// implementing `Drop`, a generic parameter to be instantiated with a
19+
// lifetime that does not strictly outlive the owning type itself,
20+
// and that this attribute's effects are preserved when importing
21+
// the type from another crate.
22+
//
23+
// See also ../dropck-eyepatch.rs for more information about the general
24+
// structure of the test.
25+
26+
use std::fmt;
27+
28+
pub struct Dt<A: fmt::Debug>(pub &'static str, pub A);
29+
pub struct Dr<'a, B:'a+fmt::Debug>(pub &'static str, pub &'a B);
30+
pub struct Pt<A,B: fmt::Debug>(pub &'static str, pub A, pub B);
31+
pub struct Pr<'a, 'b, B:'a+'b+fmt::Debug>(pub &'static str, pub &'a B, pub &'b B);
32+
pub struct St<A: fmt::Debug>(pub &'static str, pub A);
33+
pub struct Sr<'a, B:'a+fmt::Debug>(pub &'static str, pub &'a B);
34+
35+
impl<A: fmt::Debug> Drop for Dt<A> {
36+
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
37+
}
38+
impl<'a, B: fmt::Debug> Drop for Dr<'a, B> {
39+
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
40+
}
41+
unsafe impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
42+
// (unsafe to access self.1 due to #[may_dangle] on A)
43+
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
44+
}
45+
unsafe impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
46+
// (unsafe to access self.1 due to #[may_dangle] on 'a)
47+
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
48+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// aux-build:dropck_eyepatch_extern_crate.rs
12+
13+
// The point of this test is to illustrate that the `#[may_dangle]`
14+
// attribute specifically allows, in the context of a type
15+
// implementing `Drop`, a generic parameter to be instantiated with a
16+
// lifetime that does not strictly outlive the owning type itself,
17+
// and that this attribute's effects are preserved when importing
18+
// the type from another crate.
19+
//
20+
// See also dropck-eyepatch.rs for more information about the general
21+
// structure of the test.
22+
23+
extern crate dropck_eyepatch_extern_crate as other;
24+
25+
use other::{Dt,Dr,Pt,Pr,St,Sr};
26+
27+
fn main() {
28+
use std::cell::Cell;
29+
let c_long;
30+
let (c, mut dt, mut dr, mut pt, mut pr, st, sr)
31+
: (Cell<_>, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>);
32+
c_long = Cell::new(1);
33+
c = Cell::new(1);
34+
35+
// No error: sufficiently long-lived state can be referenced in dtors
36+
dt = Dt("dt", &c_long);
37+
dr = Dr("dr", &c_long);
38+
// Error: destructor order imprecisely modelled
39+
dt = Dt("dt", &c); //~ ERROR `c` does not live long enough
40+
dr = Dr("dr", &c); //~ ERROR `c` does not live long enough
41+
42+
// No error: Drop impl asserts .1 (A and &'a _) are not accessed
43+
pt = Pt("pt", &c, &c_long);
44+
pr = Pr("pr", &c, &c_long);
45+
46+
// Error: Drop impl's assertion does not apply to `B` nor `&'b _`
47+
pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough
48+
pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough
49+
50+
// No error: St and Sr have no destructor.
51+
st = St("st", &c);
52+
sr = Sr("sr", &c);
53+
54+
println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0));
55+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
error: `c` does not live long enough
2+
--> $DIR/dropck-eyepatch-extern-crate.rs:39:20
3+
|
4+
39 | dt = Dt("dt", &c); //~ ERROR `c` does not live long enough
5+
| ^ does not live long enough
6+
...
7+
55 | }
8+
| - borrowed value dropped before borrower
9+
|
10+
= note: values in a scope are dropped in the opposite order they are created
11+
12+
error: `c` does not live long enough
13+
--> $DIR/dropck-eyepatch-extern-crate.rs:40:20
14+
|
15+
40 | dr = Dr("dr", &c); //~ ERROR `c` does not live long enough
16+
| ^ does not live long enough
17+
...
18+
55 | }
19+
| - borrowed value dropped before borrower
20+
|
21+
= note: values in a scope are dropped in the opposite order they are created
22+
23+
error: `c` does not live long enough
24+
--> $DIR/dropck-eyepatch-extern-crate.rs:47:29
25+
|
26+
47 | pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough
27+
| ^ does not live long enough
28+
...
29+
55 | }
30+
| - borrowed value dropped before borrower
31+
|
32+
= note: values in a scope are dropped in the opposite order they are created
33+
34+
error: `c` does not live long enough
35+
--> $DIR/dropck-eyepatch-extern-crate.rs:48:29
36+
|
37+
48 | pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough
38+
| ^ does not live long enough
39+
...
40+
55 | }
41+
| - borrowed value dropped before borrower
42+
|
43+
= note: values in a scope are dropped in the opposite order they are created
44+
45+
error: aborting due to 4 previous errors
46+
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(generic_param_attrs)]
12+
#![feature(dropck_eyepatch)]
13+
14+
// This test ensures that a use of `#[may_dangle]` is rejected if
15+
// it is not attached to an `unsafe impl`.
16+
17+
use std::fmt;
18+
19+
struct Dt<A: fmt::Debug>(&'static str, A);
20+
struct Dr<'a, B:'a+fmt::Debug>(&'static str, &'a B);
21+
struct Pt<A,B: fmt::Debug>(&'static str, A, B);
22+
struct Pr<'a, 'b, B:'a+'b+fmt::Debug>(&'static str, &'a B, &'b B);
23+
struct St<A: fmt::Debug>(&'static str, A);
24+
struct Sr<'a, B:'a+fmt::Debug>(&'static str, &'a B);
25+
26+
impl<A: fmt::Debug> Drop for Dt<A> {
27+
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
28+
}
29+
impl<'a, B: fmt::Debug> Drop for Dr<'a, B> {
30+
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
31+
}
32+
impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
33+
//~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
34+
35+
// (unsafe to access self.1 due to #[may_dangle] on A)
36+
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
37+
}
38+
impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
39+
//~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
40+
41+
// (unsafe to access self.1 due to #[may_dangle] on 'a)
42+
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
43+
}
44+
45+
fn main() {
46+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
2+
--> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:32:1
3+
|
4+
32 | impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
5+
| ^
6+
7+
error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
8+
--> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:38:1
9+
|
10+
38 | impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
11+
| ^
12+
13+
error: aborting due to 2 previous errors
14+
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(generic_param_attrs)]
12+
#![feature(dropck_eyepatch)]
13+
14+
// The point of this test is to test uses of `#[may_dangle]` attribute
15+
// where the formal declaration order (in the impl generics) does not
16+
// match the actual usage order (in the type instantiation).
17+
//
18+
// See also dropck-eyepatch.rs for more information about the general
19+
// structure of the test.
20+
21+
use std::fmt;
22+
23+
struct Dt<A: fmt::Debug>(&'static str, A);
24+
struct Dr<'a, B:'a+fmt::Debug>(&'static str, &'a B);
25+
struct Pt<A: fmt::Debug, B: fmt::Debug>(&'static str, A, B);
26+
struct Pr<'a, 'b, B:'a+'b+fmt::Debug>(&'static str, &'a B, &'b B);
27+
struct St<A: fmt::Debug>(&'static str, A);
28+
struct Sr<'a, B:'a+fmt::Debug>(&'static str, &'a B);
29+
30+
impl<A: fmt::Debug> Drop for Dt<A> {
31+
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
32+
}
33+
impl<'a, B: fmt::Debug> Drop for Dr<'a, B> {
34+
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
35+
}
36+
unsafe impl<B: fmt::Debug, #[may_dangle] A: fmt::Debug> Drop for Pt<A, B> {
37+
// (unsafe to access self.1 due to #[may_dangle] on A)
38+
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
39+
}
40+
unsafe impl<'b, #[may_dangle] 'a, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
41+
// (unsafe to access self.1 due to #[may_dangle] on 'a)
42+
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
43+
}
44+
45+
fn main() {
46+
use std::cell::Cell;
47+
let c_long;
48+
let (c, mut dt, mut dr, mut pt, mut pr, st, sr)
49+
: (Cell<_>, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>);
50+
c_long = Cell::new(1);
51+
c = Cell::new(1);
52+
53+
// No error: sufficiently long-lived state can be referenced in dtors
54+
dt = Dt("dt", &c_long);
55+
dr = Dr("dr", &c_long);
56+
// Error: destructor order imprecisely modelled
57+
dt = Dt("dt", &c); //~ ERROR `c` does not live long enough
58+
dr = Dr("dr", &c); //~ ERROR `c` does not live long enough
59+
60+
// No error: Drop impl asserts .1 (A and &'a _) are not accessed
61+
pt = Pt("pt", &c, &c_long);
62+
pr = Pr("pr", &c, &c_long);
63+
64+
// Error: Drop impl's assertion does not apply to `B` nor `&'b _`
65+
pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough
66+
pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough
67+
68+
// No error: St and Sr have no destructor.
69+
st = St("st", &c);
70+
sr = Sr("sr", &c);
71+
72+
println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0));
73+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
error: `c` does not live long enough
2+
--> $DIR/dropck-eyepatch-reorder.rs:57:20
3+
|
4+
57 | dt = Dt("dt", &c); //~ ERROR `c` does not live long enough
5+
| ^ does not live long enough
6+
...
7+
73 | }
8+
| - borrowed value dropped before borrower
9+
|
10+
= note: values in a scope are dropped in the opposite order they are created
11+
12+
error: `c` does not live long enough
13+
--> $DIR/dropck-eyepatch-reorder.rs:58:20
14+
|
15+
58 | dr = Dr("dr", &c); //~ ERROR `c` does not live long enough
16+
| ^ does not live long enough
17+
...
18+
73 | }
19+
| - borrowed value dropped before borrower
20+
|
21+
= note: values in a scope are dropped in the opposite order they are created
22+
23+
error: `c` does not live long enough
24+
--> $DIR/dropck-eyepatch-reorder.rs:65:29
25+
|
26+
65 | pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough
27+
| ^ does not live long enough
28+
...
29+
73 | }
30+
| - borrowed value dropped before borrower
31+
|
32+
= note: values in a scope are dropped in the opposite order they are created
33+
34+
error: `c` does not live long enough
35+
--> $DIR/dropck-eyepatch-reorder.rs:66:29
36+
|
37+
66 | pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough
38+
| ^ does not live long enough
39+
...
40+
73 | }
41+
| - borrowed value dropped before borrower
42+
|
43+
= note: values in a scope are dropped in the opposite order they are created
44+
45+
error: aborting due to 4 previous errors
46+

‎src/test/ui/dropck/dropck-eyepatch.rs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(generic_param_attrs)]
12+
#![feature(dropck_eyepatch)]
13+
14+
// The point of this test is to illustrate that the `#[may_dangle]`
15+
// attribute specifically allows, in the context of a type
16+
// implementing `Drop`, a generic parameter to be instantiated with a
17+
// lifetime that does not strictly outlive the owning type itself.
18+
//
19+
// Here we test that only the expected errors are issued.
20+
//
21+
// The illustration is made concrete by comparison with two variations
22+
// on the type with `#[may_dangle]`:
23+
//
24+
// 1. an analogous type that does not implement `Drop` (and thus
25+
// should exhibit maximal flexibility with respect to dropck), and
26+
//
27+
// 2. an analogous type that does not use `#[may_dangle]` (and thus
28+
// should exhibit the standard limitations imposed by dropck.
29+
//
30+
// The types in this file follow a pattern, {D,P,S}{t,r}, where:
31+
//
32+
// - D means "I implement Drop"
33+
//
34+
// - P means "I implement Drop but guarantee my (first) parameter is
35+
// pure, i.e. not accessed from the destructor"; no other parameters
36+
// are pure.
37+
//
38+
// - S means "I do not implement Drop"
39+
//
40+
// - t suffix is used when the first generic is a type
41+
//
42+
// - r suffix is used when the first generic is a lifetime.
43+
44+
use std::fmt;
45+
46+
struct Dt<A: fmt::Debug>(&'static str, A);
47+
struct Dr<'a, B:'a+fmt::Debug>(&'static str, &'a B);
48+
struct Pt<A,B: fmt::Debug>(&'static str, A, B);
49+
struct Pr<'a, 'b, B:'a+'b+fmt::Debug>(&'static str, &'a B, &'b B);
50+
struct St<A: fmt::Debug>(&'static str, A);
51+
struct Sr<'a, B:'a+fmt::Debug>(&'static str, &'a B);
52+
53+
impl<A: fmt::Debug> Drop for Dt<A> {
54+
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
55+
}
56+
impl<'a, B: fmt::Debug> Drop for Dr<'a, B> {
57+
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
58+
}
59+
unsafe impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
60+
// (unsafe to access self.1 due to #[may_dangle] on A)
61+
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
62+
}
63+
unsafe impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
64+
// (unsafe to access self.1 due to #[may_dangle] on 'a)
65+
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
66+
}
67+
68+
fn main() {
69+
use std::cell::Cell;
70+
let c_long;
71+
let (c, mut dt, mut dr, mut pt, mut pr, st, sr)
72+
: (Cell<_>, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>);
73+
c_long = Cell::new(1);
74+
c = Cell::new(1);
75+
76+
// No error: sufficiently long-lived state can be referenced in dtors
77+
dt = Dt("dt", &c_long);
78+
dr = Dr("dr", &c_long);
79+
// Error: destructor order imprecisely modelled
80+
dt = Dt("dt", &c); //~ ERROR `c` does not live long enough
81+
dr = Dr("dr", &c); //~ ERROR `c` does not live long enough
82+
83+
// No error: Drop impl asserts .1 (A and &'a _) are not accessed
84+
pt = Pt("pt", &c, &c_long);
85+
pr = Pr("pr", &c, &c_long);
86+
87+
// Error: Drop impl's assertion does not apply to `B` nor `&'b _`
88+
pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough
89+
pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough
90+
91+
// No error: St and Sr have no destructor.
92+
st = St("st", &c);
93+
sr = Sr("sr", &c);
94+
95+
println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0));
96+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
error: `c` does not live long enough
2+
--> $DIR/dropck-eyepatch.rs:80:20
3+
|
4+
80 | dt = Dt("dt", &c); //~ ERROR `c` does not live long enough
5+
| ^ does not live long enough
6+
...
7+
96 | }
8+
| - borrowed value dropped before borrower
9+
|
10+
= note: values in a scope are dropped in the opposite order they are created
11+
12+
error: `c` does not live long enough
13+
--> $DIR/dropck-eyepatch.rs:81:20
14+
|
15+
81 | dr = Dr("dr", &c); //~ ERROR `c` does not live long enough
16+
| ^ does not live long enough
17+
...
18+
96 | }
19+
| - borrowed value dropped before borrower
20+
|
21+
= note: values in a scope are dropped in the opposite order they are created
22+
23+
error: `c` does not live long enough
24+
--> $DIR/dropck-eyepatch.rs:88:29
25+
|
26+
88 | pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough
27+
| ^ does not live long enough
28+
...
29+
96 | }
30+
| - borrowed value dropped before borrower
31+
|
32+
= note: values in a scope are dropped in the opposite order they are created
33+
34+
error: `c` does not live long enough
35+
--> $DIR/dropck-eyepatch.rs:89:29
36+
|
37+
89 | pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough
38+
| ^ does not live long enough
39+
...
40+
96 | }
41+
| - borrowed value dropped before borrower
42+
|
43+
= note: values in a scope are dropped in the opposite order they are created
44+
45+
error: aborting due to 4 previous errors
46+

0 commit comments

Comments
 (0)
Please sign in to comment.