33// of terminologies might not be relevant in the context of Clippy. Note that its behavior might
44// differ from the time of `rustc` even if the name stays the same.
55
6- use clippy_config:: msrvs:: Msrv ;
6+ use clippy_config:: msrvs:: { self , Msrv } ;
77use hir:: LangItem ;
88use rustc_attr:: StableSince ;
99use 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)
4242 for bb in & * body. basic_blocks {
4343 check_terminator ( tcx, body, bb. terminator ( ) , msrv) ?;
4444 for stmt in & bb. statements {
45- check_statement ( tcx, body, def_id, stmt) ?;
45+ check_statement ( tcx, body, def_id, stmt, msrv ) ?;
4646 }
4747 }
4848 Ok ( ( ) )
@@ -102,13 +102,14 @@ fn check_rvalue<'tcx>(
102102 def_id : DefId ,
103103 rvalue : & Rvalue < ' tcx > ,
104104 span : Span ,
105+ msrv : & Msrv ,
105106) -> McfResult {
106107 match rvalue {
107108 Rvalue :: ThreadLocalRef ( _) => Err ( ( span, "cannot access thread local storage in const fn" . into ( ) ) ) ,
108109 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 )
110111 } ,
111- Rvalue :: CopyForDeref ( place) => check_place ( tcx, * place, span, body) ,
112+ Rvalue :: CopyForDeref ( place) => check_place ( tcx, * place, span, body, msrv ) ,
112113 Rvalue :: Repeat ( operand, _)
113114 | Rvalue :: Use ( operand)
114115 | Rvalue :: Cast (
@@ -122,7 +123,7 @@ fn check_rvalue<'tcx>(
122123 | CastKind :: PointerCoercion ( PointerCoercion :: MutToConstPointer | PointerCoercion :: ArrayToPointer ) ,
123124 operand,
124125 _,
125- ) => check_operand ( tcx, operand, span, body) ,
126+ ) => check_operand ( tcx, operand, span, body, msrv ) ,
126127 Rvalue :: Cast (
127128 CastKind :: PointerCoercion (
128129 PointerCoercion :: UnsafeFnPointer
@@ -141,7 +142,7 @@ fn check_rvalue<'tcx>(
141142 } ;
142143 let unsized_ty = tcx. struct_tail_erasing_lifetimes ( pointee_ty, tcx. param_env ( def_id) ) ;
143144 if let ty:: Slice ( _) | ty:: Str = unsized_ty. kind ( ) {
144- check_operand ( tcx, op, span, body) ?;
145+ check_operand ( tcx, op, span, body, msrv ) ?;
145146 // Casting/coercing things to slices is fine.
146147 Ok ( ( ) )
147148 } else {
@@ -162,8 +163,8 @@ fn check_rvalue<'tcx>(
162163 ) ) ,
163164 // binops are fine on integers
164165 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 ) ?;
167168 let ty = lhs. ty ( body, tcx) ;
168169 if ty. is_integral ( ) || ty. is_bool ( ) || ty. is_char ( ) {
169170 Ok ( ( ) )
@@ -179,14 +180,14 @@ fn check_rvalue<'tcx>(
179180 Rvalue :: UnaryOp ( _, operand) => {
180181 let ty = operand. ty ( body, tcx) ;
181182 if ty. is_integral ( ) || ty. is_bool ( ) {
182- check_operand ( tcx, operand, span, body)
183+ check_operand ( tcx, operand, span, body, msrv )
183184 } else {
184185 Err ( ( span, "only int and `bool` operations are stable in const fn" . into ( ) ) )
185186 }
186187 } ,
187188 Rvalue :: Aggregate ( _, operands) => {
188189 for operand in operands {
189- check_operand ( tcx, operand, span, body) ?;
190+ check_operand ( tcx, operand, span, body, msrv ) ?;
190191 }
191192 Ok ( ( ) )
192193 } ,
@@ -198,28 +199,29 @@ fn check_statement<'tcx>(
198199 body : & Body < ' tcx > ,
199200 def_id : DefId ,
200201 statement : & Statement < ' tcx > ,
202+ msrv : & Msrv ,
201203) -> McfResult {
202204 let span = statement. source_info . span ;
203205 match & statement. kind {
204206 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 )
207209 } ,
208210
209- StatementKind :: FakeRead ( box ( _, place) ) => check_place ( tcx, * place, span, body) ,
211+ StatementKind :: FakeRead ( box ( _, place) ) => check_place ( tcx, * place, span, body, msrv ) ,
210212 // just an assignment
211213 StatementKind :: SetDiscriminant { place, .. } | StatementKind :: Deinit ( place) => {
212- check_place ( tcx, * * place, span, body)
214+ check_place ( tcx, * * place, span, body, msrv )
213215 } ,
214216
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 ) ,
216218
217219 StatementKind :: Intrinsic ( box NonDivergingIntrinsic :: CopyNonOverlapping (
218220 rustc_middle:: mir:: CopyNonOverlapping { dst, src, count } ,
219221 ) ) => {
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 )
223225 } ,
224226 // These are all NOPs
225227 StatementKind :: StorageLive ( _)
@@ -233,7 +235,13 @@ fn check_statement<'tcx>(
233235 }
234236}
235237
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 {
237245 match operand {
238246 Operand :: Move ( place) => {
239247 if !place. projection . as_ref ( ) . is_empty ( )
@@ -245,33 +253,37 @@ fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, b
245253 ) ) ;
246254 }
247255
248- check_place ( tcx, * place, span, body)
256+ check_place ( tcx, * place, span, body, msrv )
249257 } ,
250- Operand :: Copy ( place) => check_place ( tcx, * place, span, body) ,
258+ Operand :: Copy ( place) => check_place ( tcx, * place, span, body, msrv ) ,
251259 Operand :: Constant ( c) => match c. check_static_ptr ( tcx) {
252260 Some ( _) => Err ( ( span, "cannot access `static` items in const fn" . into ( ) ) ) ,
253261 None => Ok ( ( ) ) ,
254262 } ,
255263 }
256264}
257265
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 {
259267 for ( base, elem) in place. as_ref ( ) . iter_projections ( ) {
260268 match elem {
261269 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 ( ) ) ) ;
268272 }
269273 } ,
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+ } ,
270283 ProjectionElem :: ConstantIndex { .. }
271284 | ProjectionElem :: OpaqueCast ( ..)
272285 | ProjectionElem :: Downcast ( ..)
273286 | ProjectionElem :: Subslice { .. }
274- | ProjectionElem :: Deref
275287 | ProjectionElem :: Subtype ( _)
276288 | ProjectionElem :: Index ( _) => { } ,
277289 }
@@ -304,7 +316,7 @@ fn check_terminator<'tcx>(
304316 }
305317 Ok ( ( ) )
306318 } ,
307- TerminatorKind :: SwitchInt { discr, targets : _ } => check_operand ( tcx, discr, span, body) ,
319+ TerminatorKind :: SwitchInt { discr, targets : _ } => check_operand ( tcx, discr, span, body, msrv ) ,
308320 TerminatorKind :: CoroutineDrop | TerminatorKind :: Yield { .. } => {
309321 Err ( ( span, "const fn coroutines are unstable" . into ( ) ) )
310322 } ,
@@ -341,10 +353,10 @@ fn check_terminator<'tcx>(
341353 ) ) ;
342354 }
343355
344- check_operand ( tcx, func, span, body) ?;
356+ check_operand ( tcx, func, span, body, msrv ) ?;
345357
346358 for arg in args {
347- check_operand ( tcx, & arg. node , span, body) ?;
359+ check_operand ( tcx, & arg. node , span, body, msrv ) ?;
348360 }
349361 Ok ( ( ) )
350362 } else {
@@ -357,7 +369,7 @@ fn check_terminator<'tcx>(
357369 msg : _,
358370 target : _,
359371 unwind : _,
360- } => check_operand ( tcx, cond, span, body) ,
372+ } => check_operand ( tcx, cond, span, body, msrv ) ,
361373 TerminatorKind :: InlineAsm { .. } => Err ( ( span, "cannot use inline assembly in const fn" . into ( ) ) ) ,
362374 }
363375}
0 commit comments