Rollup merge of #123588 - tgross35:stabilize-assert_unchecked, r=dtolnay · model-checking/verify-rust-std@b184a84 (original) (raw)

`@@ -111,41 +111,92 @@ pub const unsafe fn unreachable_unchecked() -> ! {

`

111

111

``

112

112

`` /// Makes a soundness promise to the compiler that cond holds.

``

113

113

`///

`

114

``

`-

/// This may allow the optimizer to simplify things,

`

115

``

`-

/// but it might also make the generated code slower.

`

116

``

`-

/// Either way, calling it will most likely make compilation take longer.

`

``

114

`+

/// This may allow the optimizer to simplify things, but it might also make the generated code

`

``

115

`+

/// slower. Either way, calling it will most likely make compilation take longer.

`

117

116

`///

`

118

``

`-

/// This is a situational tool for micro-optimization, and is allowed to do nothing.

`

119

``

`-

/// Any use should come with a repeatable benchmark to show the value

`

120

``

`-

/// and allow removing it later should the optimizer get smarter and no longer need it.

`

``

117

`+

/// You may know this from other places as

`

``

118

`` +

/// llvm.assume or, in C,

``

``

119

`` +

/// __builtin_assume.

``

121

120

`///

`

122

``

`-

/// The more complicated the condition the less likely this is to be fruitful.

`

123

``

`` -

/// For example, assert_unchecked(foo.is_sorted()) is a complex enough value

``

124

``

`-

/// that the compiler is unlikely to be able to take advantage of it.

`

``

121

`+

/// This promotes a correctness requirement to a soundness requirement. Don't do that without

`

``

122

`+

/// very good reason.

`

125

123

`///

`

126

``

`` -

/// There's also no need to assert_unchecked basic properties of things. For

``

127

``

`` -

/// example, the compiler already knows the range of count_ones, so there's no

``

128

``

`` -

/// benefit to let n = u32::count_ones(x); assert_unchecked(n <= u32::BITS);.

``

``

124

`+

/// # Usage

`

129

125

`///

`

130

``

`` -

/// If ever you're tempted to write assert_unchecked(false), then you're

``

131

``

`` -

/// actually looking for [unreachable_unchecked()].

``

``

126

`+

/// This is a situational tool for micro-optimization, and is allowed to do nothing. Any use

`

``

127

`+

/// should come with a repeatable benchmark to show the value, with the expectation to drop it

`

``

128

`+

/// later should the optimizer get smarter and no longer need it.

`

132

129

`///

`

133

``

`-

/// You may know this from other places

`

134

``

`` -

/// as llvm.assume

``

135

``

`` -

/// or __builtin_assume.

``

``

130

`+

/// The more complicated the condition, the less likely this is to be useful. For example,

`

``

131

`` +

/// assert_unchecked(foo.is_sorted()) is a complex enough value that the compiler is unlikely

``

``

132

`+

/// to be able to take advantage of it.

`

136

133

`///

`

137

``

`-

/// This promotes a correctness requirement to a soundness requirement.

`

138

``

`-

/// Don't do that without very good reason.

`

``

134

`` +

/// There's also no need to assert_unchecked basic properties of things. For example, the

``

``

135

`` +

/// compiler already knows the range of count_ones, so there is no benefit to

``

``

136

`` +

/// let n = u32::count_ones(x); assert_unchecked(n <= u32::BITS);.

``

``

137

`+

///

`

``

138

`` +

/// assert_unchecked is logically equivalent to if !cond { unreachable_unchecked(); }. If

``

``

139

`` +

/// ever you are tempted to write assert_unchecked(false), you should instead use

``

``

140

`` +

/// [unreachable_unchecked()] directly.

``

139

141

`///

`

140

142

`/// # Safety

`

141

143

`///

`

142

``

`` -

/// cond must be true. It's immediate UB to call this with false.

``

``

144

`` +

/// cond must be true. It is immediate UB to call this with false.

``

``

145

`+

///

`

``

146

`+

/// # Example

`

``

147

`+

///

`

``

148


/// ```

``

149

`+

/// use core::hint;

`

143

150

`///

`

``

151

`+

/// /// # Safety

`

``

152

`+

/// ///

`

``

153

`` +

/// /// p must be nonnull and valid

``

``

154

`+

/// pub unsafe fn next_value(p: *const i32) -> i32 {

`

``

155

`` +

/// // SAFETY: caller invariants guarantee that p is not null

``

``

156

`+

/// unsafe { hint::assert_unchecked(!p.is_null()) }

`

``

157

`+

///

`

``

158

`+

/// if p.is_null() {

`

``

159

`+

/// return -1;

`

``

160

`+

/// } else {

`

``

161

`` +

/// // SAFETY: caller invariants guarantee that p is valid

``

``

162

`+

/// unsafe { *p + 1 }

`

``

163

`+

/// }

`

``

164

`+

/// }

`

``

165


/// ```

``

166

`+

///

`

``

167

`` +

/// Without the assert_unchecked, the above function produces the following with optimizations

``

``

168

`+

/// enabled:

`

``

169

`+

///

`

``

170


/// ```asm

``

171

`+

/// next_value:

`

``

172

`+

/// test rdi, rdi

`

``

173

`+

/// je .LBB0_1

`

``

174

`+

/// mov eax, dword ptr [rdi]

`

``

175

`+

/// inc eax

`

``

176

`+

/// ret

`

``

177

`+

/// .LBB0_1:

`

``

178

`+

/// mov eax, -1

`

``

179

`+

/// ret

`

``

180


/// ```

``

181

`+

///

`

``

182

`+

/// Adding the assertion allows the optimizer to remove the extra check:

`

``

183

`+

///

`

``

184


/// ```asm

``

185

`+

/// next_value:

`

``

186

`+

/// mov eax, dword ptr [rdi]

`

``

187

`+

/// inc eax

`

``

188

`+

/// ret

`

``

189


/// ```

``

190

`+

///

`

``

191

`+

/// This example is quite unlike anything that would be used in the real world: it is redundant

`

``

192

`+

/// to put an an assertion right next to code that checks the same thing, and dereferencing a

`

``

193

`+

/// pointer already has the builtin assumption that it is nonnull. However, it illustrates the

`

``

194

`+

/// kind of changes the optimizer can make even when the behavior is less obviously related.

`

``

195

`+

#[track_caller]

`

144

196

`#[inline(always)]

`

145

197

`#[doc(alias = "assume")]

`

146

``

`-

#[track_caller]

`

147

``

`-

#[unstable(feature = "hint_assert_unchecked", issue = "119131")]

`

148

``

`-

#[rustc_const_unstable(feature = "const_hint_assert_unchecked", issue = "119131")]

`

``

198

`+

#[stable(feature = "hint_assert_unchecked", since = "CURRENT_RUSTC_VERSION")]

`

``

199

`+

#[rustc_const_stable(feature = "hint_assert_unchecked", since = "CURRENT_RUSTC_VERSION")]

`

149

200

`pub const unsafe fn assert_unchecked(cond: bool) {

`

150

201

`` // SAFETY: The caller promised cond is true.

``

151

202

`unsafe {

`