Skip to content

Commit 9a649c3

Browse files
committed
Require destructors using #[may_dangle] to use unsafe impl.
1 parent 7d2d5bc commit 9a649c3

File tree

4 files changed

+116
-11
lines changed

4 files changed

+116
-11
lines changed

src/librustc/hir/mod.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,36 @@ impl Generics {
330330
}
331331
}
332332

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+
333363
/// A `where` clause in a definition
334364
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
335365
pub struct WhereClause {

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/diagnostics.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2819,6 +2819,23 @@ 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+
struct Foo<X>(X);
2828+
impl<#[may_dangle] X> Drop for Foo {
2829+
fn drop(&mut self) { }
2830+
}
2831+
```
2832+
2833+
In this example, we are asserting that the destructor for `Foo` will not
2834+
access any data of type `X`, and require this assertion to be true for
2835+
overall safety in our program. The compiler does not currently attempt to
2836+
verify this assertion; therefore we must tag this `impl` as unsafe.
2837+
"##,
2838+
28222839
E0318: r##"
28232840
Default impls for a trait must be located in the same crate where the trait was
28242841
defined. For more information see the [opt-in builtin traits RFC](https://github
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+
}

0 commit comments

Comments
 (0)