Skip to content

Commit 7d2d5bc

Browse files
committed
Code for enforcing #[may_dangle] attribute.
1 parent e8ccc68 commit 7d2d5bc

File tree

1 file changed

+91
-15
lines changed

1 file changed

+91
-15
lines changed

src/librustc_typeck/check/dropck.rs

Lines changed: 91 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -402,16 +402,27 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>(
402402
// unbounded type parameter `T`, we must resume the recursive
403403
// analysis on `T` (since it would be ignored by
404404
// 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(());
405+
let dropck_kind = has_dtor_of_interest(tcx, ty);
406+
debug!("iterate_over_potentially_unsafe_regions_in_type \
407+
ty: {:?} dropck_kind: {:?}", ty, dropck_kind);
408+
match dropck_kind {
409+
DropckKind::NoBorrowedDataAccessedInMyDtor => {
410+
// The maximally blind attribute.
411+
}
412+
DropckKind::BorrowedDataMustStrictlyOutliveSelf => {
413+
cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span),
414+
ty, tcx.mk_region(ty::ReScope(cx.parent_scope)));
415+
return Ok(());
416+
}
417+
DropckKind::RevisedSelf(revised_ty) => {
418+
cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span),
419+
revised_ty, tcx.mk_region(ty::ReScope(cx.parent_scope)));
420+
// Do not return early from this case; we want
421+
// to recursively process the internal structure of Self
422+
// (because even though the Drop for Self has been asserted
423+
// safe, the types instantiated for the generics of Self
424+
// may themselves carry dropck constraints.)
425+
}
415426
}
416427

417428
debug!("iterate_over_potentially_unsafe_regions_in_type \
@@ -492,16 +503,81 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>(
492503
}
493504
}
494505

506+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
507+
enum DropckKind<'tcx> {
508+
/// The "safe" kind; i.e. conservatively assume any borrow
509+
/// accessed by dtor, and therefore such data must strictly
510+
/// outlive self.
511+
///
512+
/// Equivalent to RevisedTy with no change to the self type.
513+
///
514+
/// FIXME: this name may not be general enough; it should be
515+
/// talking about Phantom lifetimes rather than just borrows.
516+
///
517+
/// (actually, pnkfelix is not 100% sure that's the right
518+
/// viewpoint. If I'm holding a phantom lifetime just to
519+
/// constrain a reference type that occurs solely in *negative*
520+
/// type positions, then my destructor cannot itself ever actually
521+
/// access such references, right? And don't we end up essentially
522+
/// requring people to put a fake borrow inside a PhantomData in
523+
/// order to make phantom lifetimes work anyway?)
524+
BorrowedDataMustStrictlyOutliveSelf,
525+
526+
/// The nearly completely-unsafe kind.
527+
///
528+
/// Equivalent to RevisedSelf with *all* parameters remapped to ()
529+
/// (maybe...?)
530+
NoBorrowedDataAccessedInMyDtor,
531+
532+
/// Assume all borrowed data access by dtor occurs as if Self has the
533+
/// type carried by this variant. In practice this means that some
534+
/// of the type parameters are remapped to `()`, because the developer
535+
/// has asserted that the destructor will not access their contents.
536+
RevisedSelf(Ty<'tcx>),
537+
}
538+
539+
/// Returns the classification of what kind of check should be applied
540+
/// to `ty`, which may include a revised type where some of the type
541+
/// parameters are re-mapped to `()` to reflect the destructor's
542+
/// "purity" with respect to their actual contents.
495543
fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
496-
ty: Ty<'tcx>) -> bool {
544+
ty: Ty<'tcx>) -> DropckKind<'tcx> {
497545
match ty.sty {
498-
ty::TyAdt(def, _) => {
499-
def.is_dtorck(tcx)
546+
ty::TyAdt(adt_def, substs) => {
547+
if !adt_def.is_dtorck(tcx) {
548+
return DropckKind::NoBorrowedDataAccessedInMyDtor;
549+
}
550+
551+
// Find the `impl<..> Drop for _` to inspect any
552+
// attributes attached to the impl's generics.
553+
let opt_dtor_method = adt_def.destructor();
554+
let dtor_method = if let Some(dtor_method) = opt_dtor_method {
555+
dtor_method
556+
} else {
557+
return DropckKind::BorrowedDataMustStrictlyOutliveSelf;
558+
};
559+
let method = tcx.impl_or_trait_item(dtor_method);
560+
let substs = Substs::for_item(tcx,
561+
method.container().id(),
562+
|def, _| if def.pure_wrt_drop {
563+
tcx.mk_region(ty::ReStatic)
564+
} else {
565+
substs.region_for_def(def)
566+
},
567+
|def, _| if def.pure_wrt_drop {
568+
tcx.mk_nil()
569+
} else {
570+
substs.type_for_def(def)
571+
});
572+
let revised_ty = tcx.mk_adt(adt_def, &substs);
573+
return DropckKind::RevisedSelf(revised_ty);
500574
}
501575
ty::TyTrait(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
502576
debug!("ty: {:?} isn't known, and therefore is a dropck type", ty);
503-
true
577+
return DropckKind::BorrowedDataMustStrictlyOutliveSelf;
504578
},
505-
_ => false
579+
_ => {
580+
return DropckKind::NoBorrowedDataAccessedInMyDtor;
581+
}
506582
}
507583
}

0 commit comments

Comments
 (0)