Rollup merge of #37117 - pnkfelix:may-dangle-attr, r=nikomatsakis

`#[may_dangle]` attribute

`#[may_dangle]` attribute

Second step of #34761. Last big hurdle before we can work in earnest towards Allocator integration (#32838)

Note: I am not clear if this is *also* a syntax-breaking change that needs to be part of a breaking-batch.
This commit is contained in:
Eduard-Mihai Burtescu 2016-10-19 07:59:59 +03:00 committed by GitHub
commit 373fcd1bd3
27 changed files with 1098 additions and 36 deletions

View File

@ -401,6 +401,7 @@ impl<'a> LoweringContext<'a> {
bounds: self.lower_bounds(&tp.bounds), bounds: self.lower_bounds(&tp.bounds),
default: tp.default.as_ref().map(|x| self.lower_ty(x)), default: tp.default.as_ref().map(|x| self.lower_ty(x)),
span: tp.span, span: tp.span,
pure_wrt_drop: tp.attrs.iter().any(|attr| attr.check_name("may_dangle")),
} }
} }
@ -420,6 +421,7 @@ impl<'a> LoweringContext<'a> {
hir::LifetimeDef { hir::LifetimeDef {
lifetime: self.lower_lifetime(&l.lifetime), lifetime: self.lower_lifetime(&l.lifetime),
bounds: self.lower_lifetimes(&l.bounds), bounds: self.lower_lifetimes(&l.bounds),
pure_wrt_drop: l.attrs.iter().any(|attr| attr.check_name("may_dangle")),
} }
} }

View File

@ -95,6 +95,7 @@ impl fmt::Debug for Lifetime {
pub struct LifetimeDef { pub struct LifetimeDef {
pub lifetime: Lifetime, pub lifetime: Lifetime,
pub bounds: HirVec<Lifetime>, pub bounds: HirVec<Lifetime>,
pub pure_wrt_drop: bool,
} }
/// A "Path" is essentially Rust's notion of a name; for instance: /// A "Path" is essentially Rust's notion of a name; for instance:
@ -290,6 +291,7 @@ pub struct TyParam {
pub bounds: TyParamBounds, pub bounds: TyParamBounds,
pub default: Option<P<Ty>>, pub default: Option<P<Ty>>,
pub span: Span, pub span: Span,
pub pure_wrt_drop: bool,
} }
/// Represents lifetimes and type parameters attached to a declaration /// Represents lifetimes and type parameters attached to a declaration
@ -328,6 +330,36 @@ impl Generics {
} }
} }
pub enum UnsafeGeneric {
Region(LifetimeDef, &'static str),
Type(TyParam, &'static str),
}
impl UnsafeGeneric {
pub fn attr_name(&self) -> &'static str {
match *self {
UnsafeGeneric::Region(_, s) => s,
UnsafeGeneric::Type(_, s) => s,
}
}
}
impl Generics {
pub fn carries_unsafe_attr(&self) -> Option<UnsafeGeneric> {
for r in &self.lifetimes {
if r.pure_wrt_drop {
return Some(UnsafeGeneric::Region(r.clone(), "may_dangle"));
}
}
for t in &self.ty_params {
if t.pure_wrt_drop {
return Some(UnsafeGeneric::Type(t.clone(), "may_dangle"));
}
}
return None;
}
}
/// A `where` clause in a definition /// A `where` clause in a definition
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct WhereClause { pub struct WhereClause {

View File

@ -1231,16 +1231,17 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
lifetime: hir::Lifetime, lifetime: hir::Lifetime,
region_names: &HashSet<ast::Name>) region_names: &HashSet<ast::Name>)
-> hir::HirVec<hir::TyParam> { -> hir::HirVec<hir::TyParam> {
ty_params.iter().map(|ty_param| { ty_params.into_iter().map(|ty_param| {
let bounds = self.rebuild_ty_param_bounds(ty_param.bounds.clone(), let bounds = self.rebuild_ty_param_bounds(ty_param.bounds,
lifetime, lifetime,
region_names); region_names);
hir::TyParam { hir::TyParam {
name: ty_param.name, name: ty_param.name,
id: ty_param.id, id: ty_param.id,
bounds: bounds, bounds: bounds,
default: ty_param.default.clone(), default: ty_param.default,
span: ty_param.span, span: ty_param.span,
pure_wrt_drop: ty_param.pure_wrt_drop,
} }
}).collect() }).collect()
} }
@ -1299,8 +1300,11 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
-> hir::Generics { -> hir::Generics {
let mut lifetimes = Vec::new(); let mut lifetimes = Vec::new();
for lt in add { for lt in add {
lifetimes.push(hir::LifetimeDef { lifetime: *lt, lifetimes.push(hir::LifetimeDef {
bounds: hir::HirVec::new() }); lifetime: *lt,
bounds: hir::HirVec::new(),
pure_wrt_drop: false,
});
} }
for lt in &generics.lifetimes { for lt in &generics.lifetimes {
if keep.contains(&lt.lifetime.name) || if keep.contains(&lt.lifetime.name) ||

View File

@ -680,6 +680,11 @@ pub struct TypeParameterDef<'tcx> {
pub default_def_id: DefId, // for use in error reporing about defaults pub default_def_id: DefId, // for use in error reporing about defaults
pub default: Option<Ty<'tcx>>, pub default: Option<Ty<'tcx>>,
pub object_lifetime_default: ObjectLifetimeDefault<'tcx>, pub object_lifetime_default: ObjectLifetimeDefault<'tcx>,
/// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute
/// on generic parameter `T`, asserts data behind the parameter
/// `T` won't be accessed during the parent type's `Drop` impl.
pub pure_wrt_drop: bool,
} }
#[derive(Clone, RustcEncodable, RustcDecodable)] #[derive(Clone, RustcEncodable, RustcDecodable)]
@ -688,6 +693,11 @@ pub struct RegionParameterDef<'tcx> {
pub def_id: DefId, pub def_id: DefId,
pub index: u32, pub index: u32,
pub bounds: Vec<&'tcx ty::Region>, pub bounds: Vec<&'tcx ty::Region>,
/// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute
/// on generic parameter `'a`, asserts data of lifetime `'a`
/// won't be accessed during the parent type's `Drop` impl.
pub pure_wrt_drop: bool,
} }
impl<'tcx> RegionParameterDef<'tcx> { impl<'tcx> RegionParameterDef<'tcx> {
@ -732,6 +742,14 @@ impl<'tcx> Generics<'tcx> {
pub fn count(&self) -> usize { pub fn count(&self) -> usize {
self.parent_count() + self.own_count() self.parent_count() + self.own_count()
} }
pub fn region_param(&self, param: &EarlyBoundRegion) -> &RegionParameterDef<'tcx> {
&self.regions[param.index as usize - self.has_self as usize]
}
pub fn type_param(&self, param: &ParamTy) -> &TypeParameterDef<'tcx> {
&self.types[param.idx as usize - self.has_self as usize - self.regions.len()]
}
} }
/// Bounds on generics. /// Bounds on generics.

View File

@ -716,6 +716,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> {
default: self.default.fold_with(folder), default: self.default.fold_with(folder),
default_def_id: self.default_def_id, default_def_id: self.default_def_id,
object_lifetime_default: self.object_lifetime_default.fold_with(folder), object_lifetime_default: self.object_lifetime_default.fold_with(folder),
pure_wrt_drop: self.pure_wrt_drop,
} }
} }
@ -754,6 +755,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef<'tcx> {
def_id: self.def_id, def_id: self.def_id,
index: self.index, index: self.index,
bounds: self.bounds.fold_with(folder), bounds: self.bounds.fold_with(folder),
pure_wrt_drop: self.pure_wrt_drop,
} }
} }

View File

@ -71,7 +71,8 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
ccx: &CrateCtxt<'a, 'tcx>, ccx: &CrateCtxt<'a, 'tcx>,
drop_impl_did: DefId, drop_impl_did: DefId,
drop_impl_ty: Ty<'tcx>, drop_impl_ty: Ty<'tcx>,
self_type_did: DefId) -> Result<(), ()> self_type_did: DefId)
-> Result<(), ()>
{ {
let tcx = ccx.tcx; let tcx = ccx.tcx;
let drop_impl_node_id = tcx.map.as_local_node_id(drop_impl_did).unwrap(); 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>(
drop_impl_did: DefId, drop_impl_did: DefId,
dtor_predicates: &ty::GenericPredicates<'tcx>, dtor_predicates: &ty::GenericPredicates<'tcx>,
self_type_did: DefId, self_type_did: DefId,
self_to_impl_substs: &Substs<'tcx>) -> Result<(), ()> { self_to_impl_substs: &Substs<'tcx>)
-> Result<(), ()>
{
// Here is an example, analogous to that from // Here is an example, analogous to that from
// `compare_impl_method`. // `compare_impl_method`.
@ -350,7 +353,8 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>(
cx: &mut DropckContext<'a, 'b, 'gcx, 'tcx>, cx: &mut DropckContext<'a, 'b, 'gcx, 'tcx>,
context: TypeContext, context: TypeContext,
ty: Ty<'tcx>, ty: Ty<'tcx>,
depth: usize) -> Result<(), Error<'tcx>> depth: usize)
-> Result<(), Error<'tcx>>
{ {
let tcx = cx.rcx.tcx; let tcx = cx.rcx.tcx;
// Issue #22443: Watch out for overflow. While we are careful to // 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>(
// unbounded type parameter `T`, we must resume the recursive // unbounded type parameter `T`, we must resume the recursive
// analysis on `T` (since it would be ignored by // analysis on `T` (since it would be ignored by
// type_must_outlive). // type_must_outlive).
if has_dtor_of_interest(tcx, ty) { let dropck_kind = has_dtor_of_interest(tcx, ty);
debug!("iterate_over_potentially_unsafe_regions_in_type \ debug!("iterate_over_potentially_unsafe_regions_in_type \
{}ty: {} - is a dtorck type!", ty: {:?} dropck_kind: {:?}", ty, dropck_kind);
(0..depth).map(|_| ' ').collect::<String>(), match dropck_kind {
ty); DropckKind::NoBorrowedDataAccessedInMyDtor => {
// The maximally blind attribute.
cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span), }
ty, tcx.mk_region(ty::ReScope(cx.parent_scope))); DropckKind::BorrowedDataMustStrictlyOutliveSelf => {
cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span),
return Ok(()); ty, tcx.mk_region(ty::ReScope(cx.parent_scope)));
return Ok(());
}
DropckKind::RevisedSelf(revised_ty) => {
cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span),
revised_ty, tcx.mk_region(ty::ReScope(cx.parent_scope)));
// Do not return early from this case; we want
// to recursively process the internal structure of Self
// (because even though the Drop for Self has been asserted
// safe, the types instantiated for the generics of Self
// may themselves carry dropck constraints.)
}
} }
debug!("iterate_over_potentially_unsafe_regions_in_type \ debug!("iterate_over_potentially_unsafe_regions_in_type \
@ -492,16 +507,140 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>(
} }
} }
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum DropckKind<'tcx> {
/// The "safe" kind; i.e. conservatively assume any borrow
/// accessed by dtor, and therefore such data must strictly
/// outlive self.
///
/// Equivalent to RevisedTy with no change to the self type.
BorrowedDataMustStrictlyOutliveSelf,
/// The nearly completely-unsafe kind.
///
/// Equivalent to RevisedSelf with *all* parameters remapped to ()
/// (maybe...?)
NoBorrowedDataAccessedInMyDtor,
/// Assume all borrowed data access by dtor occurs as if Self has the
/// type carried by this variant. In practice this means that some
/// of the type parameters are remapped to `()` (and some lifetime
/// parameters remapped to `'static`), because the developer has asserted
/// that the destructor will not access their contents.
RevisedSelf(Ty<'tcx>),
}
/// Returns the classification of what kind of check should be applied
/// to `ty`, which may include a revised type where some of the type
/// parameters are re-mapped to `()` to reflect the destructor's
/// "purity" with respect to their actual contents.
fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
ty: Ty<'tcx>) -> bool { ty: Ty<'tcx>)
-> DropckKind<'tcx> {
match ty.sty { match ty.sty {
ty::TyAdt(def, _) => { ty::TyAdt(adt_def, substs) => {
def.is_dtorck(tcx) if !adt_def.is_dtorck(tcx) {
return DropckKind::NoBorrowedDataAccessedInMyDtor;
}
// Find the `impl<..> Drop for _` to inspect any
// attributes attached to the impl's generics.
let dtor_method = adt_def.destructor()
.expect("dtorck type without destructor impossible");
let method = tcx.impl_or_trait_item(dtor_method);
let impl_id: DefId = method.container().id();
let revised_ty = revise_self_ty(tcx, adt_def, impl_id, substs);
return DropckKind::RevisedSelf(revised_ty);
} }
ty::TyTrait(..) | ty::TyProjection(..) | ty::TyAnon(..) => { ty::TyTrait(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
debug!("ty: {:?} isn't known, and therefore is a dropck type", ty); debug!("ty: {:?} isn't known, and therefore is a dropck type", ty);
true return DropckKind::BorrowedDataMustStrictlyOutliveSelf;
}, },
_ => false _ => {
return DropckKind::NoBorrowedDataAccessedInMyDtor;
}
} }
} }
// Constructs new Ty just like the type defined by `adt_def` coupled
// with `substs`, except each type and lifetime parameter marked as
// `#[may_dangle]` in the Drop impl (identified by `impl_id`) is
// respectively mapped to `()` or `'static`.
//
// For example: If the `adt_def` maps to:
//
// enum Foo<'a, X, Y> { ... }
//
// and the `impl_id` maps to:
//
// impl<#[may_dangle] 'a, X, #[may_dangle] Y> Drop for Foo<'a, X, Y> { ... }
//
// then revises input: `Foo<'r,i64,&'r i64>` to: `Foo<'static,i64,()>`
fn revise_self_ty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
adt_def: ty::AdtDef<'tcx>,
impl_id: DefId,
substs: &Substs<'tcx>)
-> Ty<'tcx> {
// Get generics for `impl Drop` to query for `#[may_dangle]` attr.
let impl_bindings = tcx.lookup_generics(impl_id);
// Get Substs attached to Self on `impl Drop`; process in parallel
// with `substs`, replacing dangling entries as appropriate.
let self_substs = {
let impl_self_ty: Ty<'tcx> = tcx.lookup_item_type(impl_id).ty;
if let ty::TyAdt(self_adt_def, self_substs) = impl_self_ty.sty {
assert_eq!(adt_def, self_adt_def);
self_substs
} else {
bug!("Self in `impl Drop for _` must be an Adt.");
}
};
// Walk `substs` + `self_substs`, build new substs appropriate for
// `adt_def`; each non-dangling param reuses entry from `substs`.
//
// Note: The manner we map from a right-hand side (i.e. Region or
// Ty) for a given `def` to generic parameter associated with that
// right-hand side is tightly coupled to `Drop` impl constraints.
//
// E.g. we know such a Ty must be `TyParam`, because a destructor
// for `struct Foo<X>` is defined via `impl<Y> Drop for Foo<Y>`,
// and never by (for example) `impl<Z> Drop for Foo<Vec<Z>>`.
let substs = Substs::for_item(
tcx,
adt_def.did,
|def, _| {
let r_orig = substs.region_for_def(def);
let impl_self_orig = self_substs.region_for_def(def);
let r = if let ty::Region::ReEarlyBound(ref ebr) = *impl_self_orig {
if impl_bindings.region_param(ebr).pure_wrt_drop {
tcx.mk_region(ty::ReStatic)
} else {
r_orig
}
} else {
bug!("substs for an impl must map regions to ReEarlyBound");
};
debug!("has_dtor_of_interest mapping def {:?} orig {:?} to {:?}",
def, r_orig, r);
r
},
|def, _| {
let t_orig = substs.type_for_def(def);
let impl_self_orig = self_substs.type_for_def(def);
let t = if let ty::TypeVariants::TyParam(ref pt) = impl_self_orig.sty {
if impl_bindings.type_param(pt).pure_wrt_drop {
tcx.mk_nil()
} else {
t_orig
}
} else {
bug!("substs for an impl must map types to TyParam");
};
debug!("has_dtor_of_interest mapping def {:?} orig {:?} {:?} to {:?} {:?}",
def, t_orig, t_orig.sty, t, t.sty);
t
});
return tcx.mk_adt(adt_def, &substs);
}

View File

@ -13,7 +13,7 @@
use rustc::ty::TyCtxt; use rustc::ty::TyCtxt;
use rustc::hir::intravisit; use rustc::hir::intravisit;
use rustc::hir; use rustc::hir::{self, Unsafety};
pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
let mut orphan = UnsafetyChecker { tcx: tcx }; let mut orphan = UnsafetyChecker { tcx: tcx };
@ -27,6 +27,7 @@ struct UnsafetyChecker<'cx, 'tcx: 'cx> {
impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> { impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
fn check_unsafety_coherence(&mut self, fn check_unsafety_coherence(&mut self,
item: &'v hir::Item, item: &'v hir::Item,
impl_generics: Option<&hir::Generics>,
unsafety: hir::Unsafety, unsafety: hir::Unsafety,
polarity: hir::ImplPolarity) { polarity: hir::ImplPolarity) {
match self.tcx.impl_trait_ref(self.tcx.map.local_def_id(item.id)) { match self.tcx.impl_trait_ref(self.tcx.map.local_def_id(item.id)) {
@ -47,15 +48,16 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
Some(trait_ref) => { Some(trait_ref) => {
let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id); let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id);
match (trait_def.unsafety, unsafety, polarity) { let unsafe_attr = impl_generics.and_then(|g| g.carries_unsafe_attr());
(hir::Unsafety::Unsafe, hir::Unsafety::Unsafe, hir::ImplPolarity::Negative) => { match (trait_def.unsafety, unsafe_attr, unsafety, polarity) {
(_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative) => {
span_err!(self.tcx.sess, span_err!(self.tcx.sess,
item.span, item.span,
E0198, E0198,
"negative implementations are not unsafe"); "negative implementations are not unsafe");
} }
(hir::Unsafety::Normal, hir::Unsafety::Unsafe, _) => { (Unsafety::Normal, None, Unsafety::Unsafe, _) => {
span_err!(self.tcx.sess, span_err!(self.tcx.sess,
item.span, item.span,
E0199, E0199,
@ -63,7 +65,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
trait_ref); trait_ref);
} }
(hir::Unsafety::Unsafe, hir::Unsafety::Normal, hir::ImplPolarity::Positive) => { (Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => {
span_err!(self.tcx.sess, span_err!(self.tcx.sess,
item.span, item.span,
E0200, E0200,
@ -71,9 +73,19 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
trait_ref); trait_ref);
} }
(hir::Unsafety::Unsafe, hir::Unsafety::Normal, hir::ImplPolarity::Negative) | (Unsafety::Normal, Some(g), Unsafety::Normal, hir::ImplPolarity::Positive) =>
(hir::Unsafety::Unsafe, hir::Unsafety::Unsafe, hir::ImplPolarity::Positive) | {
(hir::Unsafety::Normal, hir::Unsafety::Normal, _) => { span_err!(self.tcx.sess,
item.span,
E0569,
"requires an `unsafe impl` declaration due to `#[{}]` attribute",
g.attr_name());
}
(_, _, Unsafety::Normal, hir::ImplPolarity::Negative) |
(Unsafety::Unsafe, _, Unsafety::Unsafe, hir::ImplPolarity::Positive) |
(Unsafety::Normal, Some(_), Unsafety::Unsafe, hir::ImplPolarity::Positive) |
(Unsafety::Normal, None, Unsafety::Normal, _) => {
// OK // OK
} }
} }
@ -86,10 +98,10 @@ impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
fn visit_item(&mut self, item: &'v hir::Item) { fn visit_item(&mut self, item: &'v hir::Item) {
match item.node { match item.node {
hir::ItemDefaultImpl(unsafety, _) => { hir::ItemDefaultImpl(unsafety, _) => {
self.check_unsafety_coherence(item, unsafety, hir::ImplPolarity::Positive); self.check_unsafety_coherence(item, None, unsafety, hir::ImplPolarity::Positive);
} }
hir::ItemImpl(unsafety, polarity, ..) => { hir::ItemImpl(unsafety, polarity, ref generics, ..) => {
self.check_unsafety_coherence(item, unsafety, polarity); self.check_unsafety_coherence(item, Some(generics), unsafety, polarity);
} }
_ => {} _ => {}
} }

View File

@ -1482,6 +1482,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
default_def_id: tcx.map.local_def_id(parent), default_def_id: tcx.map.local_def_id(parent),
default: None, default: None,
object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault,
pure_wrt_drop: false,
}; };
tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone()); tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone());
opt_self = Some(def); opt_self = Some(def);
@ -1526,7 +1527,8 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
def_id: tcx.map.local_def_id(l.lifetime.id), def_id: tcx.map.local_def_id(l.lifetime.id),
bounds: l.bounds.iter().map(|l| { bounds: l.bounds.iter().map(|l| {
ast_region_to_region(tcx, l) ast_region_to_region(tcx, l)
}).collect() }).collect(),
pure_wrt_drop: l.pure_wrt_drop,
} }
}).collect::<Vec<_>>(); }).collect::<Vec<_>>();
@ -1926,6 +1928,7 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
default_def_id: ccx.tcx.map.local_def_id(parent), default_def_id: ccx.tcx.map.local_def_id(parent),
default: default, default: default,
object_lifetime_default: object_lifetime_default, object_lifetime_default: object_lifetime_default,
pure_wrt_drop: param.pure_wrt_drop,
}; };
if def.name == keywords::SelfType.name() { if def.name == keywords::SelfType.name() {

View File

@ -2819,6 +2819,26 @@ not a distinct static type. Likewise, it's not legal to attempt to
behavior for specific enum variants. behavior for specific enum variants.
"##, "##,
E0569: r##"
If an impl has a generic parameter with the `#[may_dangle]` attribute, then
that impl must be declared as an `unsafe impl. For example:
```compile_fail,E0569
#![feature(generic_param_attrs)]
#![feature(dropck_eyepatch)]
struct Foo<X>(X);
impl<#[may_dangle] X> Drop for Foo<X> {
fn drop(&mut self) { }
}
```
In this example, we are asserting that the destructor for `Foo` will not
access any data of type `X`, and require this assertion to be true for
overall safety in our program. The compiler does not currently attempt to
verify this assertion; therefore we must tag this `impl` as unsafe.
"##,
E0318: r##" E0318: r##"
Default impls for a trait must be located in the same crate where the trait was Default impls for a trait must be located in the same crate where the trait was
defined. For more information see the [opt-in builtin traits RFC](https://github defined. For more information see the [opt-in builtin traits RFC](https://github

View File

@ -167,6 +167,9 @@ declare_features! (
// RFC 1238 // RFC 1238
(active, dropck_parametricity, "1.3.0", Some(28498)), (active, dropck_parametricity, "1.3.0", Some(28498)),
// Allows using the may_dangle attribute; RFC 1327
(active, dropck_eyepatch, "1.10.0", Some(34761)),
// Allows the use of custom attributes; RFC 572 // Allows the use of custom attributes; RFC 572
(active, custom_attribute, "1.0.0", Some(29642)), (active, custom_attribute, "1.0.0", Some(29642)),
@ -616,6 +619,11 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat
"unsafe_destructor_blind_to_params has unstable semantics \ "unsafe_destructor_blind_to_params has unstable semantics \
and may be removed in the future", and may be removed in the future",
cfg_fn!(dropck_parametricity))), cfg_fn!(dropck_parametricity))),
("may_dangle",
Normal,
Gated("dropck_eyepatch",
"may_dangle has unstable semantics and may be removed in the future",
cfg_fn!(dropck_eyepatch))),
("unwind", Whitelisted, Gated("unwind_attributes", "#[unwind] is experimental", ("unwind", Whitelisted, Gated("unwind_attributes", "#[unwind] is experimental",
cfg_fn!(unwind_attributes))), cfg_fn!(unwind_attributes))),

View File

@ -1361,6 +1361,7 @@ impl<'a> State<'a> {
if comma { if comma {
try!(self.word_space(",")) try!(self.word_space(","))
} }
try!(self.print_outer_attributes_inline(&lifetime_def.attrs));
try!(self.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds)); try!(self.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds));
comma = true; comma = true;
} }
@ -2803,6 +2804,7 @@ impl<'a> State<'a> {
try!(self.commasep(Inconsistent, &ints[..], |s, &idx| { try!(self.commasep(Inconsistent, &ints[..], |s, &idx| {
if idx < generics.lifetimes.len() { if idx < generics.lifetimes.len() {
let lifetime_def = &generics.lifetimes[idx]; let lifetime_def = &generics.lifetimes[idx];
try!(s.print_outer_attributes_inline(&lifetime_def.attrs));
s.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds) s.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds)
} else { } else {
let idx = idx - generics.lifetimes.len(); let idx = idx - generics.lifetimes.len();
@ -2816,6 +2818,7 @@ impl<'a> State<'a> {
} }
pub fn print_ty_param(&mut self, param: &ast::TyParam) -> io::Result<()> { pub fn print_ty_param(&mut self, param: &ast::TyParam) -> io::Result<()> {
try!(self.print_outer_attributes_inline(&param.attrs));
try!(self.print_ident(param.ident)); try!(self.print_ident(param.ident));
try!(self.print_bounds(":", &param.bounds)); try!(self.print_bounds(":", &param.bounds));
match param.default { match param.default {

View File

@ -0,0 +1,18 @@
// Copyright 2016 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(optin_builtin_traits)]
struct Foo;
unsafe impl !Clone for Foo { } //~ ERROR negative implementations are not unsafe [E0198]
fn main() {
}

View File

@ -12,7 +12,8 @@
struct Foo; struct Foo;
unsafe impl !Clone for Foo { } //~ ERROR E0199 trait Bar { }
unsafe impl Bar for Foo { } //~ ERROR implementing the trait `Bar` is not unsafe [E0199]
fn main() { fn main() {
} }

View File

@ -0,0 +1,20 @@
// Copyright 2016 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Check that `may_dangle` is rejected if `dropck_eyepatch` feature gate is absent.
#![feature(generic_param_attrs)]
struct Pt<A>(A);
impl<#[may_dangle] A> Drop for Pt<A> {
//~^ ERROR may_dangle has unstable semantics and may be removed in the future
//~| HELP add #![feature(dropck_eyepatch)] to the crate attributes to enable
fn drop(&mut self) { }
}

View File

@ -0,0 +1,61 @@
// Copyright 2016 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(generic_param_attrs)]
#![feature(dropck_eyepatch)]
// The point of this test is to illustrate that the `#[may_dangle]`
// attribute specifically allows, in the context of a type
// implementing `Drop`, a generic parameter to be instantiated with a
// lifetime that does not strictly outlive the owning type itself,
// and that this attributes effects are preserved when importing
// the type from another crate.
//
// See also dropck-eyepatch.rs for more information about the general
// structure of the test.
use std::cell::RefCell;
pub trait Foo { fn foo(&self, _: &str); }
pub struct Dt<A: Foo>(pub &'static str, pub A);
pub struct Dr<'a, B:'a+Foo>(pub &'static str, pub &'a B);
pub struct Pt<A,B: Foo>(pub &'static str, pub A, pub B);
pub struct Pr<'a, 'b, B:'a+'b+Foo>(pub &'static str, pub &'a B, pub &'b B);
pub struct St<A: Foo>(pub &'static str, pub A);
pub struct Sr<'a, B:'a+Foo>(pub &'static str, pub &'a B);
impl<A: Foo> Drop for Dt<A> {
fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); }
}
impl<'a, B: Foo> Drop for Dr<'a, B> {
fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); }
}
unsafe impl<#[may_dangle] A, B: Foo> Drop for Pt<A, B> {
// (unsafe to access self.1 due to #[may_dangle] on A)
fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); }
}
unsafe impl<#[may_dangle] 'a, 'b, B: Foo> Drop for Pr<'a, 'b, B> {
// (unsafe to access self.1 due to #[may_dangle] on 'a)
fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); }
}
impl Foo for RefCell<String> {
fn foo(&self, s: &str) {
let s2 = format!("{}|{}", *self.borrow(), s);
*self.borrow_mut() = s2;
}
}
impl<'a, T:Foo> Foo for &'a T {
fn foo(&self, s: &str) {
(*self).foo(s);
}
}

View File

@ -0,0 +1,48 @@
// Copyright 2016 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// aux-build:dropck_eyepatch_extern_crate.rs
extern crate dropck_eyepatch_extern_crate as other;
use other::{Dt,Dr,Pt,Pr,St,Sr};
fn main() {
use std::cell::RefCell;
struct CheckOnDrop(RefCell<String>, &'static str);
impl Drop for CheckOnDrop {
fn drop(&mut self) { assert_eq!(*self.0.borrow(), self.1); }
}
let c_long;
let (c, dt, dr, pt, pr, st, sr)
: (CheckOnDrop, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>);
c_long = CheckOnDrop(RefCell::new("c_long".to_string()),
"c_long|pr|pt|dr|dt");
c = CheckOnDrop(RefCell::new("c".to_string()),
"c");
// No error: sufficiently long-lived state can be referenced in dtors
dt = Dt("dt", &c_long.0);
dr = Dr("dr", &c_long.0);
// No error: Drop impl asserts .1 (A and &'a _) are not accessed
pt = Pt("pt", &c.0, &c_long.0);
pr = Pr("pr", &c.0, &c_long.0);
// No error: St and Sr have no destructor.
st = St("st", &c.0);
sr = Sr("sr", &c.0);
println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0));
assert_eq!(*c_long.0.borrow(), "c_long");
assert_eq!(*c.0.borrow(), "c");
}

View File

@ -0,0 +1,89 @@
// Copyright 2016 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(generic_param_attrs)]
#![feature(dropck_eyepatch)]
// The point of this test is to test uses of `#[may_dangle]` attribute
// where the formal declaration order (in the impl generics) does not
// match the actual usage order (in the type instantiation).
//
// See also dropck-eyepatch.rs for more information about the general
// structure of the test.
trait Foo { fn foo(&self, _: &str); }
struct Dt<A: Foo>(&'static str, A);
struct Dr<'a, B:'a+Foo>(&'static str, &'a B);
struct Pt<A: Foo, B: Foo>(&'static str, A, B);
struct Pr<'a, 'b, B:'a+'b+Foo>(&'static str, &'a B, &'b B);
struct St<A: Foo>(&'static str, A);
struct Sr<'a, B:'a+Foo>(&'static str, &'a B);
impl<A: Foo> Drop for Dt<A> {
fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); }
}
impl<'a, B: Foo> Drop for Dr<'a, B> {
fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); }
}
unsafe impl<B: Foo, #[may_dangle] A: Foo> Drop for Pt<A, B> {
// (unsafe to access self.1 due to #[may_dangle] on A)
fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); }
}
unsafe impl<'b, #[may_dangle] 'a, B: Foo> Drop for Pr<'a, 'b, B> {
// (unsafe to access self.1 due to #[may_dangle] on 'a)
fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); }
}
fn main() {
use std::cell::RefCell;
impl Foo for RefCell<String> {
fn foo(&self, s: &str) {
let s2 = format!("{}|{}", *self.borrow(), s);
*self.borrow_mut() = s2;
}
}
impl<'a, T:Foo> Foo for &'a T {
fn foo(&self, s: &str) {
(*self).foo(s);
}
}
struct CheckOnDrop(RefCell<String>, &'static str);
impl Drop for CheckOnDrop {
fn drop(&mut self) { assert_eq!(*self.0.borrow(), self.1); }
}
let c_long;
let (c, dt, dr, pt, pr, st, sr)
: (CheckOnDrop, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>);
c_long = CheckOnDrop(RefCell::new("c_long".to_string()),
"c_long|pr|pt|dr|dt");
c = CheckOnDrop(RefCell::new("c".to_string()),
"c");
// No error: sufficiently long-lived state can be referenced in dtors
dt = Dt("dt", &c_long.0);
dr = Dr("dr", &c_long.0);
// No error: Drop impl asserts .1 (A and &'a _) are not accessed
pt = Pt("pt", &c.0, &c_long.0);
pr = Pr("pr", &c.0, &c_long.0);
// No error: St and Sr have no destructor.
st = St("st", &c.0);
sr = Sr("sr", &c.0);
println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0));
assert_eq!(*c_long.0.borrow(), "c_long");
assert_eq!(*c.0.borrow(), "c");
}

View File

@ -0,0 +1,112 @@
// Copyright 2016 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(generic_param_attrs)]
#![feature(dropck_eyepatch)]
// The point of this test is to illustrate that the `#[may_dangle]`
// attribute specifically allows, in the context of a type
// implementing `Drop`, a generic parameter to be instantiated with a
// lifetime that does not strictly outlive the owning type itself.
//
// Here we test that a model use of `#[may_dangle]` will compile and run.
//
// The illustration is made concrete by comparison with two variations
// on the type with `#[may_dangle]`:
//
// 1. an analogous type that does not implement `Drop` (and thus
// should exhibit maximal flexibility with respect to dropck), and
//
// 2. an analogous type that does not use `#[may_dangle]` (and thus
// should exhibit the standard limitations imposed by dropck.
//
// The types in this file follow a pattern, {D,P,S}{t,r}, where:
//
// - D means "I implement Drop"
//
// - P means "I implement Drop but guarantee my (first) parameter is
// pure, i.e. not accessed from the destructor"; no other parameters
// are pure.
//
// - S means "I do not implement Drop"
//
// - t suffix is used when the first generic is a type
//
// - r suffix is used when the first generic is a lifetime.
trait Foo { fn foo(&self, _: &str); }
struct Dt<A: Foo>(&'static str, A);
struct Dr<'a, B:'a+Foo>(&'static str, &'a B);
struct Pt<A,B: Foo>(&'static str, A, B);
struct Pr<'a, 'b, B:'a+'b+Foo>(&'static str, &'a B, &'b B);
struct St<A: Foo>(&'static str, A);
struct Sr<'a, B:'a+Foo>(&'static str, &'a B);
impl<A: Foo> Drop for Dt<A> {
fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); }
}
impl<'a, B: Foo> Drop for Dr<'a, B> {
fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); }
}
unsafe impl<#[may_dangle] A, B: Foo> Drop for Pt<A, B> {
// (unsafe to access self.1 due to #[may_dangle] on A)
fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); }
}
unsafe impl<#[may_dangle] 'a, 'b, B: Foo> Drop for Pr<'a, 'b, B> {
// (unsafe to access self.1 due to #[may_dangle] on 'a)
fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); }
}
fn main() {
use std::cell::RefCell;
impl Foo for RefCell<String> {
fn foo(&self, s: &str) {
let s2 = format!("{}|{}", *self.borrow(), s);
*self.borrow_mut() = s2;
}
}
impl<'a, T:Foo> Foo for &'a T {
fn foo(&self, s: &str) {
(*self).foo(s);
}
}
struct CheckOnDrop(RefCell<String>, &'static str);
impl Drop for CheckOnDrop {
fn drop(&mut self) { assert_eq!(*self.0.borrow(), self.1); }
}
let c_long;
let (c, dt, dr, pt, pr, st, sr)
: (CheckOnDrop, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>);
c_long = CheckOnDrop(RefCell::new("c_long".to_string()),
"c_long|pr|pt|dr|dt");
c = CheckOnDrop(RefCell::new("c".to_string()),
"c");
// No error: sufficiently long-lived state can be referenced in dtors
dt = Dt("dt", &c_long.0);
dr = Dr("dr", &c_long.0);
// No error: Drop impl asserts .1 (A and &'a _) are not accessed
pt = Pt("pt", &c.0, &c_long.0);
pr = Pr("pr", &c.0, &c_long.0);
// No error: St and Sr have no destructor.
st = St("st", &c.0);
sr = Sr("sr", &c.0);
println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0));
assert_eq!(*c_long.0.borrow(), "c_long");
assert_eq!(*c.0.borrow(), "c");
}

View File

@ -0,0 +1,48 @@
// Copyright 2016 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(generic_param_attrs)]
#![feature(dropck_eyepatch)]
// This is a support file for ../dropck-eyepatch-extern-crate.rs
//
// The point of this test is to illustrate that the `#[may_dangle]`
// attribute specifically allows, in the context of a type
// implementing `Drop`, a generic parameter to be instantiated with a
// lifetime that does not strictly outlive the owning type itself,
// and that this attribute's effects are preserved when importing
// the type from another crate.
//
// See also ../dropck-eyepatch.rs for more information about the general
// structure of the test.
use std::fmt;
pub struct Dt<A: fmt::Debug>(pub &'static str, pub A);
pub struct Dr<'a, B:'a+fmt::Debug>(pub &'static str, pub &'a B);
pub struct Pt<A,B: fmt::Debug>(pub &'static str, pub A, pub B);
pub struct Pr<'a, 'b, B:'a+'b+fmt::Debug>(pub &'static str, pub &'a B, pub &'b B);
pub struct St<A: fmt::Debug>(pub &'static str, pub A);
pub struct Sr<'a, B:'a+fmt::Debug>(pub &'static str, pub &'a B);
impl<A: fmt::Debug> Drop for Dt<A> {
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
}
impl<'a, B: fmt::Debug> Drop for Dr<'a, B> {
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
}
unsafe impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
// (unsafe to access self.1 due to #[may_dangle] on A)
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
}
unsafe impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
// (unsafe to access self.1 due to #[may_dangle] on 'a)
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
}

View File

@ -0,0 +1,55 @@
// Copyright 2016 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// aux-build:dropck_eyepatch_extern_crate.rs
// The point of this test is to illustrate that the `#[may_dangle]`
// attribute specifically allows, in the context of a type
// implementing `Drop`, a generic parameter to be instantiated with a
// lifetime that does not strictly outlive the owning type itself,
// and that this attribute's effects are preserved when importing
// the type from another crate.
//
// See also dropck-eyepatch.rs for more information about the general
// structure of the test.
extern crate dropck_eyepatch_extern_crate as other;
use other::{Dt,Dr,Pt,Pr,St,Sr};
fn main() {
use std::cell::Cell;
let c_long;
let (c, mut dt, mut dr, mut pt, mut pr, st, sr)
: (Cell<_>, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>);
c_long = Cell::new(1);
c = Cell::new(1);
// No error: sufficiently long-lived state can be referenced in dtors
dt = Dt("dt", &c_long);
dr = Dr("dr", &c_long);
// Error: destructor order imprecisely modelled
dt = Dt("dt", &c); //~ ERROR `c` does not live long enough
dr = Dr("dr", &c); //~ ERROR `c` does not live long enough
// No error: Drop impl asserts .1 (A and &'a _) are not accessed
pt = Pt("pt", &c, &c_long);
pr = Pr("pr", &c, &c_long);
// Error: Drop impl's assertion does not apply to `B` nor `&'b _`
pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough
pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough
// No error: St and Sr have no destructor.
st = St("st", &c);
sr = Sr("sr", &c);
println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0));
}

View File

@ -0,0 +1,46 @@
error: `c` does not live long enough
--> $DIR/dropck-eyepatch-extern-crate.rs:39:20
|
39 | dt = Dt("dt", &c); //~ ERROR `c` does not live long enough
| ^ does not live long enough
...
55 | }
| - borrowed value dropped before borrower
|
= note: values in a scope are dropped in the opposite order they are created
error: `c` does not live long enough
--> $DIR/dropck-eyepatch-extern-crate.rs:40:20
|
40 | dr = Dr("dr", &c); //~ ERROR `c` does not live long enough
| ^ does not live long enough
...
55 | }
| - borrowed value dropped before borrower
|
= note: values in a scope are dropped in the opposite order they are created
error: `c` does not live long enough
--> $DIR/dropck-eyepatch-extern-crate.rs:47:29
|
47 | pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough
| ^ does not live long enough
...
55 | }
| - borrowed value dropped before borrower
|
= note: values in a scope are dropped in the opposite order they are created
error: `c` does not live long enough
--> $DIR/dropck-eyepatch-extern-crate.rs:48:29
|
48 | pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough
| ^ does not live long enough
...
55 | }
| - borrowed value dropped before borrower
|
= note: values in a scope are dropped in the opposite order they are created
error: aborting due to 4 previous errors

View File

@ -0,0 +1,46 @@
// Copyright 2016 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(generic_param_attrs)]
#![feature(dropck_eyepatch)]
// This test ensures that a use of `#[may_dangle]` is rejected if
// it is not attached to an `unsafe impl`.
use std::fmt;
struct Dt<A: fmt::Debug>(&'static str, A);
struct Dr<'a, B:'a+fmt::Debug>(&'static str, &'a B);
struct Pt<A,B: fmt::Debug>(&'static str, A, B);
struct Pr<'a, 'b, B:'a+'b+fmt::Debug>(&'static str, &'a B, &'b B);
struct St<A: fmt::Debug>(&'static str, A);
struct Sr<'a, B:'a+fmt::Debug>(&'static str, &'a B);
impl<A: fmt::Debug> Drop for Dt<A> {
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
}
impl<'a, B: fmt::Debug> Drop for Dr<'a, B> {
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
}
impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
//~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
// (unsafe to access self.1 due to #[may_dangle] on A)
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
}
impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
//~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
// (unsafe to access self.1 due to #[may_dangle] on 'a)
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
}
fn main() {
}

View File

@ -0,0 +1,14 @@
error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
--> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:32:1
|
32 | impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
| ^
error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
--> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:38:1
|
38 | impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
| ^
error: aborting due to 2 previous errors

View File

@ -0,0 +1,73 @@
// Copyright 2016 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(generic_param_attrs)]
#![feature(dropck_eyepatch)]
// The point of this test is to test uses of `#[may_dangle]` attribute
// where the formal declaration order (in the impl generics) does not
// match the actual usage order (in the type instantiation).
//
// See also dropck-eyepatch.rs for more information about the general
// structure of the test.
use std::fmt;
struct Dt<A: fmt::Debug>(&'static str, A);
struct Dr<'a, B:'a+fmt::Debug>(&'static str, &'a B);
struct Pt<A: fmt::Debug, B: fmt::Debug>(&'static str, A, B);
struct Pr<'a, 'b, B:'a+'b+fmt::Debug>(&'static str, &'a B, &'b B);
struct St<A: fmt::Debug>(&'static str, A);
struct Sr<'a, B:'a+fmt::Debug>(&'static str, &'a B);
impl<A: fmt::Debug> Drop for Dt<A> {
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
}
impl<'a, B: fmt::Debug> Drop for Dr<'a, B> {
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
}
unsafe impl<B: fmt::Debug, #[may_dangle] A: fmt::Debug> Drop for Pt<A, B> {
// (unsafe to access self.1 due to #[may_dangle] on A)
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
}
unsafe impl<'b, #[may_dangle] 'a, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
// (unsafe to access self.1 due to #[may_dangle] on 'a)
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
}
fn main() {
use std::cell::Cell;
let c_long;
let (c, mut dt, mut dr, mut pt, mut pr, st, sr)
: (Cell<_>, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>);
c_long = Cell::new(1);
c = Cell::new(1);
// No error: sufficiently long-lived state can be referenced in dtors
dt = Dt("dt", &c_long);
dr = Dr("dr", &c_long);
// Error: destructor order imprecisely modelled
dt = Dt("dt", &c); //~ ERROR `c` does not live long enough
dr = Dr("dr", &c); //~ ERROR `c` does not live long enough
// No error: Drop impl asserts .1 (A and &'a _) are not accessed
pt = Pt("pt", &c, &c_long);
pr = Pr("pr", &c, &c_long);
// Error: Drop impl's assertion does not apply to `B` nor `&'b _`
pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough
pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough
// No error: St and Sr have no destructor.
st = St("st", &c);
sr = Sr("sr", &c);
println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0));
}

View File

@ -0,0 +1,46 @@
error: `c` does not live long enough
--> $DIR/dropck-eyepatch-reorder.rs:57:20
|
57 | dt = Dt("dt", &c); //~ ERROR `c` does not live long enough
| ^ does not live long enough
...
73 | }
| - borrowed value dropped before borrower
|
= note: values in a scope are dropped in the opposite order they are created
error: `c` does not live long enough
--> $DIR/dropck-eyepatch-reorder.rs:58:20
|
58 | dr = Dr("dr", &c); //~ ERROR `c` does not live long enough
| ^ does not live long enough
...
73 | }
| - borrowed value dropped before borrower
|
= note: values in a scope are dropped in the opposite order they are created
error: `c` does not live long enough
--> $DIR/dropck-eyepatch-reorder.rs:65:29
|
65 | pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough
| ^ does not live long enough
...
73 | }
| - borrowed value dropped before borrower
|
= note: values in a scope are dropped in the opposite order they are created
error: `c` does not live long enough
--> $DIR/dropck-eyepatch-reorder.rs:66:29
|
66 | pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough
| ^ does not live long enough
...
73 | }
| - borrowed value dropped before borrower
|
= note: values in a scope are dropped in the opposite order they are created
error: aborting due to 4 previous errors

View File

@ -0,0 +1,96 @@
// Copyright 2016 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(generic_param_attrs)]
#![feature(dropck_eyepatch)]
// The point of this test is to illustrate that the `#[may_dangle]`
// attribute specifically allows, in the context of a type
// implementing `Drop`, a generic parameter to be instantiated with a
// lifetime that does not strictly outlive the owning type itself.
//
// Here we test that only the expected errors are issued.
//
// The illustration is made concrete by comparison with two variations
// on the type with `#[may_dangle]`:
//
// 1. an analogous type that does not implement `Drop` (and thus
// should exhibit maximal flexibility with respect to dropck), and
//
// 2. an analogous type that does not use `#[may_dangle]` (and thus
// should exhibit the standard limitations imposed by dropck.
//
// The types in this file follow a pattern, {D,P,S}{t,r}, where:
//
// - D means "I implement Drop"
//
// - P means "I implement Drop but guarantee my (first) parameter is
// pure, i.e. not accessed from the destructor"; no other parameters
// are pure.
//
// - S means "I do not implement Drop"
//
// - t suffix is used when the first generic is a type
//
// - r suffix is used when the first generic is a lifetime.
use std::fmt;
struct Dt<A: fmt::Debug>(&'static str, A);
struct Dr<'a, B:'a+fmt::Debug>(&'static str, &'a B);
struct Pt<A,B: fmt::Debug>(&'static str, A, B);
struct Pr<'a, 'b, B:'a+'b+fmt::Debug>(&'static str, &'a B, &'b B);
struct St<A: fmt::Debug>(&'static str, A);
struct Sr<'a, B:'a+fmt::Debug>(&'static str, &'a B);
impl<A: fmt::Debug> Drop for Dt<A> {
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
}
impl<'a, B: fmt::Debug> Drop for Dr<'a, B> {
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); }
}
unsafe impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
// (unsafe to access self.1 due to #[may_dangle] on A)
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
}
unsafe impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
// (unsafe to access self.1 due to #[may_dangle] on 'a)
fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
}
fn main() {
use std::cell::Cell;
let c_long;
let (c, mut dt, mut dr, mut pt, mut pr, st, sr)
: (Cell<_>, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>);
c_long = Cell::new(1);
c = Cell::new(1);
// No error: sufficiently long-lived state can be referenced in dtors
dt = Dt("dt", &c_long);
dr = Dr("dr", &c_long);
// Error: destructor order imprecisely modelled
dt = Dt("dt", &c); //~ ERROR `c` does not live long enough
dr = Dr("dr", &c); //~ ERROR `c` does not live long enough
// No error: Drop impl asserts .1 (A and &'a _) are not accessed
pt = Pt("pt", &c, &c_long);
pr = Pr("pr", &c, &c_long);
// Error: Drop impl's assertion does not apply to `B` nor `&'b _`
pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough
pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough
// No error: St and Sr have no destructor.
st = St("st", &c);
sr = Sr("sr", &c);
println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0));
}

View File

@ -0,0 +1,46 @@
error: `c` does not live long enough
--> $DIR/dropck-eyepatch.rs:80:20
|
80 | dt = Dt("dt", &c); //~ ERROR `c` does not live long enough
| ^ does not live long enough
...
96 | }
| - borrowed value dropped before borrower
|
= note: values in a scope are dropped in the opposite order they are created
error: `c` does not live long enough
--> $DIR/dropck-eyepatch.rs:81:20
|
81 | dr = Dr("dr", &c); //~ ERROR `c` does not live long enough
| ^ does not live long enough
...
96 | }
| - borrowed value dropped before borrower
|
= note: values in a scope are dropped in the opposite order they are created
error: `c` does not live long enough
--> $DIR/dropck-eyepatch.rs:88:29
|
88 | pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough
| ^ does not live long enough
...
96 | }
| - borrowed value dropped before borrower
|
= note: values in a scope are dropped in the opposite order they are created
error: `c` does not live long enough
--> $DIR/dropck-eyepatch.rs:89:29
|
89 | pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough
| ^ does not live long enough
...
96 | }
| - borrowed value dropped before borrower
|
= note: values in a scope are dropped in the opposite order they are created
error: aborting due to 4 previous errors