Rollup merge of #130279 - theemathas:manually-drop-docs, r=thomcc,tra… · qinheping/verify-rust-std@805d196 (original) (raw)

1

1

`use crate::ops::{Deref, DerefMut, DerefPure};

`

2

2

`use crate::ptr;

`

3

3

``

4

``

`` -

/// A wrapper to inhibit the compiler from automatically calling T’s destructor.

``

5

``

`-

/// This wrapper is 0-cost.

`

``

4

`` +

/// A wrapper to inhibit the compiler from automatically calling T’s

``

``

5

`+

/// destructor. This wrapper is 0-cost.

`

6

6

`///

`

7

7

`` /// ManuallyDrop<T> is guaranteed to have the same layout and bit validity as

``

8

``

`` -

/// T, and is subject to the same layout optimizations as T. As a consequence,

``

9

``

`-

/// it has no effect on the assumptions that the compiler makes about its

`

10

``

`` -

/// contents. For example, initializing a ManuallyDrop<&mut T> with [mem::zeroed]

``

11

``

`-

/// is undefined behavior. If you need to handle uninitialized data, use

`

12

``

`` -

/// [MaybeUninit<T>] instead.

``

``

8

`` +

/// T, and is subject to the same layout optimizations as T. As a

``

``

9

`+

/// consequence, it has no effect on the assumptions that the compiler makes

`

``

10

`` +

/// about its contents. For example, initializing a ManuallyDrop<&mut T> with

``

``

11

`` +

/// [mem::zeroed] is undefined behavior. If you need to handle uninitialized

``

``

12

`` +

/// data, use [MaybeUninit<T>] instead.

``

13

13

`///

`

14

``

`` -

/// Note that accessing the value inside a ManuallyDrop<T> is safe.

``

15

``

`` -

/// This means that a ManuallyDrop<T> whose content has been dropped must not

``

16

``

`-

/// be exposed through a public safe API.

`

17

``

`` -

/// Correspondingly, ManuallyDrop::drop is unsafe.

``

``

14

`` +

/// Note that accessing the value inside a ManuallyDrop<T> is safe. This means

``

``

15

`` +

/// that a ManuallyDrop<T> whose content has been dropped must not be exposed

``

``

16

`` +

/// through a public safe API. Correspondingly, ManuallyDrop::drop is unsafe.

``

18

17

`///

`

19

``

`` -

/// # ManuallyDrop and drop order.

``

``

18

`` +

/// # ManuallyDrop and drop order

``

20

19

`///

`

21

20

`/// Rust has a well-defined [drop order] of values. To make sure that fields or

`

22

21

`/// locals are dropped in a specific order, reorder the declarations such that

`

`@@ -40,9 +39,116 @@ use crate::ptr;

`

40

39

`/// }

`

41

40

```` /// ```


`42`

`41`

`///

`

``

`42`

`` +

/// # Interaction with `Box`

``

``

`43`

`+

///

`

``

`44`

`` +

/// Currently, if you have a `ManuallyDrop<T>`, where the type `T` is a `Box` or

``

``

`45`

`` +

/// contains a `Box` inside, then dropping the `T` followed by moving the

``

``

`46`

`` +

/// `ManuallyDrop<T>` is [considered to be undefined

``

``

`47`

`+

/// behavior](https://github.com/rust-lang/unsafe-code-guidelines/issues/245).

`

``

`48`

`+

/// That is, the following code causes undefined behavior:

`

``

`49`

`+

///

`

``

`50`

```` +

/// ```no_run

``

51

`+

/// use std::mem::ManuallyDrop;

`

``

52

`+

///

`

``

53

`+

/// let mut x = ManuallyDrop::new(Box::new(42));

`

``

54

`+

/// unsafe {

`

``

55

`+

/// ManuallyDrop::drop(&mut x);

`

``

56

`+

/// }

`

``

57

`+

/// let y = x; // Undefined behavior!

`

``

58


/// ```

``

59

`+

///

`

``

60

`+

/// This is [likely to change in the

`

``

61

`+

/// future](https://rust-lang.github.io/rfcs/3336-maybe-dangling.html). In the

`

``

62

`` +

/// meantime, consider using [MaybeUninit] instead.

``

``

63

`+

///

`

``

64

`` +

/// # Safety hazards when storing ManuallyDrop in a struct or an enum.

``

``

65

`+

///

`

``

66

`+

/// Special care is needed when all of the conditions below are met:

`

``

67

`` +

/// * A struct or enum contains a ManuallyDrop.

``

``

68

`` +

/// * The ManuallyDrop is not inside a union.

``

``

69

`+

/// * The struct or enum is part of public API, or is stored in a struct or an

`

``

70

`+

/// enum that is part of public API.

`

``

71

`` +

/// * There is code that drops the contents of the ManuallyDrop field, and

``

``

72

`` +

/// this code is outside the struct or enum's Drop implementation.

``

``

73

`+

///

`

``

74

`+

/// In particular, the following hazards may occur:

`

``

75

`+

///

`

``

76

`+

/// #### Storing generic types

`

``

77

`+

///

`

``

78

`` +

/// If the ManuallyDrop contains a client-supplied generic type, the client

``

``

79

`` +

/// might provide a Box as that type. This would cause undefined behavior when

``

``

80

`+

/// the struct or enum is later moved, as mentioned in the previous section. For

`

``

81

`+

/// example, the following code causes undefined behavior:

`

``

82

`+

///

`

``

83


/// ```no_run

``

84

`+

/// use std::mem::ManuallyDrop;

`

``

85

`+

///

`

``

86

`+

/// pub struct BadOption {

`

``

87

`` +

/// // Invariant: Has been dropped iff is_some is false.

``

``

88

`+

/// value: ManuallyDrop,

`

``

89

`+

/// is_some: bool,

`

``

90

`+

/// }

`

``

91

`+

/// impl BadOption {

`

``

92

`+

/// pub fn new(value: T) -> Self {

`

``

93

`+

/// Self { value: ManuallyDrop::new(value), is_some: true }

`

``

94

`+

/// }

`

``

95

`+

/// pub fn change_to_none(&mut self) {

`

``

96

`+

/// if self.is_some {

`

``

97

`+

/// self.is_some = false;

`

``

98

`+

/// unsafe {

`

``

99

`` +

/// // SAFETY: value hasn't been dropped yet, as per the invariant

``

``

100

`+

/// // (This is actually unsound!)

`

``

101

`+

/// ManuallyDrop::drop(&mut self.value);

`

``

102

`+

/// }

`

``

103

`+

/// }

`

``

104

`+

/// }

`

``

105

`+

/// }

`

``

106

`+

///

`

``

107

`+

/// // In another crate:

`

``

108

`+

///

`

``

109

`+

/// let mut option = BadOption::new(Box::new(42));

`

``

110

`+

/// option.change_to_none();

`

``

111

`+

/// let option2 = option; // Undefined behavior!

`

``

112


/// ```

``

113

`+

///

`

``

114

`+

/// #### Deriving traits

`

``

115

`+

///

`

``

116

`` +

/// Deriving Debug, Clone, PartialEq, PartialOrd, Ord, or Hash on

``

``

117

`+

/// the struct or enum could be unsound, since the derived implementations of

`

``

118

`` +

/// these traits would access the ManuallyDrop field. For example, the

``

``

119

`+

/// following code causes undefined behavior:

`

``

120

`+

///

`

``

121


/// ```no_run

``

122

`+

/// use std::mem::ManuallyDrop;

`

``

123

`+

///

`

``

124

`` +

/// // This derive is unsound in combination with the ManuallyDrop::drop call.

``

``

125

`+

/// #[derive(Debug)]

`

``

126

`+

/// pub struct Foo {

`

``

127

`+

/// value: ManuallyDrop,

`

``

128

`+

/// }

`

``

129

`+

/// impl Foo {

`

``

130

`+

/// pub fn new() -> Self {

`

``

131

`+

/// let mut temp = Self {

`

``

132

`+

/// value: ManuallyDrop::new(String::from("Unsafe rust is hard."))

`

``

133

`+

/// };

`

``

134

`+

/// unsafe {

`

``

135

`` +

/// // SAFETY: value hasn't been dropped yet.

``

``

136

`+

/// ManuallyDrop::drop(&mut temp.value);

`

``

137

`+

/// }

`

``

138

`+

/// temp

`

``

139

`+

/// }

`

``

140

`+

/// }

`

``

141

`+

///

`

``

142

`+

/// // In another crate:

`

``

143

`+

///

`

``

144

`+

/// let foo = Foo::new();

`

``

145

`+

/// println!("{:?}", foo); // Undefined behavior!

`

``

146


/// ```

``

147

`+

///

`

43

148

`/// [drop order]: https://doc.rust-lang.org/reference/destructors.html

`

44

149

`` /// [mem::zeroed]: crate::mem::zeroed

``

45

150

`` /// [MaybeUninit<T>]: crate::mem::MaybeUninit

``

``

151

`` +

/// [MaybeUninit]: crate::mem::MaybeUninit

``

46

152

`#[stable(feature = "manually_drop", since = "1.20.0")]

`

47

153

`#[lang = "manually_drop"]

`

48

154

`#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]

`