3
3
// of terminologies might not be relevant in the context of Clippy. Note that its behavior might
4
4
// differ from the time of `rustc` even if the name stays the same.
5
5
6
- use clippy_config:: msrvs:: Msrv ;
6
+ use clippy_config:: msrvs:: { self , Msrv } ;
7
7
use hir:: LangItem ;
8
8
use rustc_attr:: StableSince ;
9
9
use rustc_const_eval:: transform:: check_consts:: ConstCx ;
@@ -42,7 +42,7 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv)
42
42
for bb in & * body. basic_blocks {
43
43
check_terminator ( tcx, body, bb. terminator ( ) , msrv) ?;
44
44
for stmt in & bb. statements {
45
- check_statement ( tcx, body, def_id, stmt) ?;
45
+ check_statement ( tcx, body, def_id, stmt, msrv ) ?;
46
46
}
47
47
}
48
48
Ok ( ( ) )
@@ -102,13 +102,14 @@ fn check_rvalue<'tcx>(
102
102
def_id : DefId ,
103
103
rvalue : & Rvalue < ' tcx > ,
104
104
span : Span ,
105
+ msrv : & Msrv ,
105
106
) -> McfResult {
106
107
match rvalue {
107
108
Rvalue :: ThreadLocalRef ( _) => Err ( ( span, "cannot access thread local storage in const fn" . into ( ) ) ) ,
108
109
Rvalue :: Len ( place) | Rvalue :: Discriminant ( place) | Rvalue :: Ref ( _, _, place) | Rvalue :: AddressOf ( _, place) => {
109
- check_place ( tcx, * place, span, body)
110
+ check_place ( tcx, * place, span, body, msrv )
110
111
} ,
111
- Rvalue :: CopyForDeref ( place) => check_place ( tcx, * place, span, body) ,
112
+ Rvalue :: CopyForDeref ( place) => check_place ( tcx, * place, span, body, msrv ) ,
112
113
Rvalue :: Repeat ( operand, _)
113
114
| Rvalue :: Use ( operand)
114
115
| Rvalue :: Cast (
@@ -122,7 +123,7 @@ fn check_rvalue<'tcx>(
122
123
| CastKind :: PointerCoercion ( PointerCoercion :: MutToConstPointer | PointerCoercion :: ArrayToPointer ) ,
123
124
operand,
124
125
_,
125
- ) => check_operand ( tcx, operand, span, body) ,
126
+ ) => check_operand ( tcx, operand, span, body, msrv ) ,
126
127
Rvalue :: Cast (
127
128
CastKind :: PointerCoercion (
128
129
PointerCoercion :: UnsafeFnPointer
@@ -141,7 +142,7 @@ fn check_rvalue<'tcx>(
141
142
} ;
142
143
let unsized_ty = tcx. struct_tail_erasing_lifetimes ( pointee_ty, tcx. param_env ( def_id) ) ;
143
144
if let ty:: Slice ( _) | ty:: Str = unsized_ty. kind ( ) {
144
- check_operand ( tcx, op, span, body) ?;
145
+ check_operand ( tcx, op, span, body, msrv ) ?;
145
146
// Casting/coercing things to slices is fine.
146
147
Ok ( ( ) )
147
148
} else {
@@ -162,8 +163,8 @@ fn check_rvalue<'tcx>(
162
163
) ) ,
163
164
// binops are fine on integers
164
165
Rvalue :: BinaryOp ( _, box ( lhs, rhs) ) | Rvalue :: CheckedBinaryOp ( _, box ( lhs, rhs) ) => {
165
- check_operand ( tcx, lhs, span, body) ?;
166
- check_operand ( tcx, rhs, span, body) ?;
166
+ check_operand ( tcx, lhs, span, body, msrv ) ?;
167
+ check_operand ( tcx, rhs, span, body, msrv ) ?;
167
168
let ty = lhs. ty ( body, tcx) ;
168
169
if ty. is_integral ( ) || ty. is_bool ( ) || ty. is_char ( ) {
169
170
Ok ( ( ) )
@@ -179,14 +180,14 @@ fn check_rvalue<'tcx>(
179
180
Rvalue :: UnaryOp ( _, operand) => {
180
181
let ty = operand. ty ( body, tcx) ;
181
182
if ty. is_integral ( ) || ty. is_bool ( ) {
182
- check_operand ( tcx, operand, span, body)
183
+ check_operand ( tcx, operand, span, body, msrv )
183
184
} else {
184
185
Err ( ( span, "only int and `bool` operations are stable in const fn" . into ( ) ) )
185
186
}
186
187
} ,
187
188
Rvalue :: Aggregate ( _, operands) => {
188
189
for operand in operands {
189
- check_operand ( tcx, operand, span, body) ?;
190
+ check_operand ( tcx, operand, span, body, msrv ) ?;
190
191
}
191
192
Ok ( ( ) )
192
193
} ,
@@ -198,28 +199,29 @@ fn check_statement<'tcx>(
198
199
body : & Body < ' tcx > ,
199
200
def_id : DefId ,
200
201
statement : & Statement < ' tcx > ,
202
+ msrv : & Msrv ,
201
203
) -> McfResult {
202
204
let span = statement. source_info . span ;
203
205
match & statement. kind {
204
206
StatementKind :: Assign ( box ( place, rval) ) => {
205
- check_place ( tcx, * place, span, body) ?;
206
- check_rvalue ( tcx, body, def_id, rval, span)
207
+ check_place ( tcx, * place, span, body, msrv ) ?;
208
+ check_rvalue ( tcx, body, def_id, rval, span, msrv )
207
209
} ,
208
210
209
- StatementKind :: FakeRead ( box ( _, place) ) => check_place ( tcx, * place, span, body) ,
211
+ StatementKind :: FakeRead ( box ( _, place) ) => check_place ( tcx, * place, span, body, msrv ) ,
210
212
// just an assignment
211
213
StatementKind :: SetDiscriminant { place, .. } | StatementKind :: Deinit ( place) => {
212
- check_place ( tcx, * * place, span, body)
214
+ check_place ( tcx, * * place, span, body, msrv )
213
215
} ,
214
216
215
- StatementKind :: Intrinsic ( box NonDivergingIntrinsic :: Assume ( op) ) => check_operand ( tcx, op, span, body) ,
217
+ StatementKind :: Intrinsic ( box NonDivergingIntrinsic :: Assume ( op) ) => check_operand ( tcx, op, span, body, msrv ) ,
216
218
217
219
StatementKind :: Intrinsic ( box NonDivergingIntrinsic :: CopyNonOverlapping (
218
220
rustc_middle:: mir:: CopyNonOverlapping { dst, src, count } ,
219
221
) ) => {
220
- check_operand ( tcx, dst, span, body) ?;
221
- check_operand ( tcx, src, span, body) ?;
222
- check_operand ( tcx, count, span, body)
222
+ check_operand ( tcx, dst, span, body, msrv ) ?;
223
+ check_operand ( tcx, src, span, body, msrv ) ?;
224
+ check_operand ( tcx, count, span, body, msrv )
223
225
} ,
224
226
// These are all NOPs
225
227
StatementKind :: StorageLive ( _)
@@ -233,7 +235,13 @@ fn check_statement<'tcx>(
233
235
}
234
236
}
235
237
236
- fn check_operand < ' tcx > ( tcx : TyCtxt < ' tcx > , operand : & Operand < ' tcx > , span : Span , body : & Body < ' tcx > ) -> McfResult {
238
+ fn check_operand < ' tcx > (
239
+ tcx : TyCtxt < ' tcx > ,
240
+ operand : & Operand < ' tcx > ,
241
+ span : Span ,
242
+ body : & Body < ' tcx > ,
243
+ msrv : & Msrv ,
244
+ ) -> McfResult {
237
245
match operand {
238
246
Operand :: Move ( place) => {
239
247
if !place. projection . as_ref ( ) . is_empty ( )
@@ -245,33 +253,37 @@ fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, b
245
253
) ) ;
246
254
}
247
255
248
- check_place ( tcx, * place, span, body)
256
+ check_place ( tcx, * place, span, body, msrv )
249
257
} ,
250
- Operand :: Copy ( place) => check_place ( tcx, * place, span, body) ,
258
+ Operand :: Copy ( place) => check_place ( tcx, * place, span, body, msrv ) ,
251
259
Operand :: Constant ( c) => match c. check_static_ptr ( tcx) {
252
260
Some ( _) => Err ( ( span, "cannot access `static` items in const fn" . into ( ) ) ) ,
253
261
None => Ok ( ( ) ) ,
254
262
} ,
255
263
}
256
264
}
257
265
258
- fn check_place < ' tcx > ( tcx : TyCtxt < ' tcx > , place : Place < ' tcx > , span : Span , body : & Body < ' tcx > ) -> McfResult {
266
+ fn check_place < ' tcx > ( tcx : TyCtxt < ' tcx > , place : Place < ' tcx > , span : Span , body : & Body < ' tcx > , msrv : & Msrv ) -> McfResult {
259
267
for ( base, elem) in place. as_ref ( ) . iter_projections ( ) {
260
268
match elem {
261
269
ProjectionElem :: Field ( ..) => {
262
- let base_ty = base. ty ( body, tcx) . ty ;
263
- if let Some ( def) = base_ty. ty_adt_def ( ) {
264
- // No union field accesses in `const fn`
265
- if def. is_union ( ) {
266
- return Err ( ( span, "accessing union fields is unstable" . into ( ) ) ) ;
267
- }
270
+ if base. ty ( body, tcx) . ty . is_union ( ) && !msrv. meets ( msrvs:: CONST_FN_UNION ) {
271
+ return Err ( ( span, "accessing union fields is unstable" . into ( ) ) ) ;
268
272
}
269
273
} ,
274
+ ProjectionElem :: Deref => match base. ty ( body, tcx) . ty . kind ( ) {
275
+ ty:: RawPtr ( _, hir:: Mutability :: Mut ) => {
276
+ return Err ( ( span, "dereferencing raw mut pointer in const fn is unstable" . into ( ) ) ) ;
277
+ } ,
278
+ ty:: RawPtr ( _, hir:: Mutability :: Not ) if !msrv. meets ( msrvs:: CONST_RAW_PTR_DEREF ) => {
279
+ return Err ( ( span, "dereferencing raw const pointer in const fn is unstable" . into ( ) ) ) ;
280
+ } ,
281
+ _ => ( ) ,
282
+ } ,
270
283
ProjectionElem :: ConstantIndex { .. }
271
284
| ProjectionElem :: OpaqueCast ( ..)
272
285
| ProjectionElem :: Downcast ( ..)
273
286
| ProjectionElem :: Subslice { .. }
274
- | ProjectionElem :: Deref
275
287
| ProjectionElem :: Subtype ( _)
276
288
| ProjectionElem :: Index ( _) => { } ,
277
289
}
@@ -304,7 +316,7 @@ fn check_terminator<'tcx>(
304
316
}
305
317
Ok ( ( ) )
306
318
} ,
307
- TerminatorKind :: SwitchInt { discr, targets : _ } => check_operand ( tcx, discr, span, body) ,
319
+ TerminatorKind :: SwitchInt { discr, targets : _ } => check_operand ( tcx, discr, span, body, msrv ) ,
308
320
TerminatorKind :: CoroutineDrop | TerminatorKind :: Yield { .. } => {
309
321
Err ( ( span, "const fn coroutines are unstable" . into ( ) ) )
310
322
} ,
@@ -341,10 +353,10 @@ fn check_terminator<'tcx>(
341
353
) ) ;
342
354
}
343
355
344
- check_operand ( tcx, func, span, body) ?;
356
+ check_operand ( tcx, func, span, body, msrv ) ?;
345
357
346
358
for arg in args {
347
- check_operand ( tcx, & arg. node , span, body) ?;
359
+ check_operand ( tcx, & arg. node , span, body, msrv ) ?;
348
360
}
349
361
Ok ( ( ) )
350
362
} else {
@@ -357,7 +369,7 @@ fn check_terminator<'tcx>(
357
369
msg : _,
358
370
target : _,
359
371
unwind : _,
360
- } => check_operand ( tcx, cond, span, body) ,
372
+ } => check_operand ( tcx, cond, span, body, msrv ) ,
361
373
TerminatorKind :: InlineAsm { .. } => Err ( ( span, "cannot use inline assembly in const fn" . into ( ) ) ) ,
362
374
}
363
375
}
0 commit comments