]>
Commit | Line | Data |
---|---|---|
9346a6ac | 1 | //! Code for type-checking cast expressions. |
62682a34 SL |
2 | //! |
3 | //! A cast `e as U` is valid if one of the following holds: | |
4 | //! * `e` has type `T` and `T` coerces to `U`; *coercion-cast* | |
5 | //! * `e` has type `*T`, `U` is `*U_0`, and either `U_0: Sized` or | |
abe05a73 | 6 | //! pointer_kind(`T`) = pointer_kind(`U_0`); *ptr-ptr-cast* |
62682a34 SL |
7 | //! * `e` has type `*T` and `U` is a numeric type, while `T: Sized`; *ptr-addr-cast* |
8 | //! * `e` is an integer and `U` is `*U_0`, while `U_0: Sized`; *addr-ptr-cast* | |
9 | //! * `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast* | |
10 | //! * `e` is a C-like enum and `U` is an integer type; *enum-cast* | |
11 | //! * `e` has type `bool` or `char` and `U` is an integer; *prim-int-cast* | |
12 | //! * `e` has type `u8` and `U` is `char`; *u8-char-cast* | |
13 | //! * `e` has type `&[T; n]` and `U` is `*const T`; *array-ptr-cast* | |
14 | //! * `e` is a function pointer type and `U` has type `*T`, | |
15 | //! while `T: Sized`; *fptr-ptr-cast* | |
16 | //! * `e` is a function pointer type and `U` is an integer; *fptr-addr-cast* | |
17 | //! | |
18 | //! where `&.T` and `*T` are references of either mutability, | |
abe05a73 | 19 | //! and where pointer_kind(`T`) is the kind of the unsize info |
0731742a | 20 | //! in `T` - the vtable for a trait definition (e.g., `fmt::Display` or |
62682a34 SL |
21 | //! `Iterator`, not `Iterator<Item=u8>`) or a length (or `()` if `T: Sized`). |
22 | //! | |
23 | //! Note that lengths are not adjusted when casting raw slices - | |
24 | //! `T: *const [u16] as *const [u8]` creates a slice that only includes | |
25 | //! half of the original memory. | |
26 | //! | |
27 | //! Casting is not transitive, that is, even if `e as U1 as U2` is a valid | |
28 | //! expression, `e as U2` is not necessarily so (in fact it will only be valid if | |
29 | //! `U1` coerces to `U2`). | |
9346a6ac | 30 | |
0531ce1d | 31 | use super::FnCtxt; |
9346a6ac | 32 | |
9fa01778 | 33 | use crate::hir::def_id::DefId; |
dfeec247 | 34 | use crate::type_error_struct; |
5e7ed085 | 35 | use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; |
dfeec247 | 36 | use rustc_hir as hir; |
3dfed10e | 37 | use rustc_hir::lang_items::LangItem; |
17df50a5 | 38 | use rustc_middle::mir::Mutability; |
ba9703b0 XL |
39 | use rustc_middle::ty::adjustment::AllowTwoPhase; |
40 | use rustc_middle::ty::cast::{CastKind, CastTy}; | |
41 | use rustc_middle::ty::error::TypeError; | |
42 | use rustc_middle::ty::subst::SubstsRef; | |
43 | use rustc_middle::ty::{self, Ty, TypeAndMut, TypeFoldable}; | |
44 | use rustc_session::lint; | |
45 | use rustc_session::Session; | |
f035d41b | 46 | use rustc_span::symbol::sym; |
dfeec247 | 47 | use rustc_span::Span; |
136023e0 | 48 | use rustc_trait_selection::infer::InferCtxtExt; |
ba9703b0 XL |
49 | use rustc_trait_selection::traits; |
50 | use rustc_trait_selection::traits::error_reporting::report_object_safety_error; | |
60c5eb7d | 51 | |
9346a6ac AL |
52 | /// Reifies a cast check to be checked once we have full type information for |
53 | /// a function context. | |
94222f64 | 54 | #[derive(Debug)] |
9346a6ac | 55 | pub struct CastCheck<'tcx> { |
dfeec247 | 56 | expr: &'tcx hir::Expr<'tcx>, |
9346a6ac AL |
57 | expr_ty: Ty<'tcx>, |
58 | cast_ty: Ty<'tcx>, | |
a7813a04 | 59 | cast_span: Span, |
9346a6ac AL |
60 | span: Span, |
61 | } | |
62 | ||
abe05a73 XL |
63 | /// The kind of pointer and associated metadata (thin, length or vtable) - we |
64 | /// only allow casts between fat pointers if their metadata have the same | |
65 | /// kind. | |
62682a34 | 66 | #[derive(Copy, Clone, PartialEq, Eq)] |
abe05a73 XL |
67 | enum PointerKind<'tcx> { |
68 | /// No metadata attached, ie pointer to sized type or foreign type | |
69 | Thin, | |
70 | /// A trait object | |
0731742a | 71 | Vtable(Option<DefId>), |
abe05a73 | 72 | /// Slice |
62682a34 SL |
73 | Length, |
74 | /// The unsize info of this projection | |
75 | OfProjection(&'tcx ty::ProjectionTy<'tcx>), | |
b7449926 | 76 | /// The unsize info of this opaque ty |
532ac7d7 | 77 | OfOpaque(DefId, SubstsRef<'tcx>), |
62682a34 | 78 | /// The unsize info of this parameter |
c30ab7b3 | 79 | OfParam(&'tcx ty::ParamTy), |
62682a34 SL |
80 | } |
81 | ||
dc9dc135 | 82 | impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
a7813a04 | 83 | /// Returns the kind of unsize information of t, or None |
abe05a73 | 84 | /// if t is unknown. |
dfeec247 XL |
85 | fn pointer_kind( |
86 | &self, | |
87 | t: Ty<'tcx>, | |
88 | span: Span, | |
5e7ed085 | 89 | ) -> Result<Option<PointerKind<'tcx>>, ErrorGuaranteed> { |
ff7c6d11 XL |
90 | debug!("pointer_kind({:?}, {:?})", t, span); |
91 | ||
fc512014 | 92 | let t = self.resolve_vars_if_possible(t); |
ff7c6d11 | 93 | |
5e7ed085 FG |
94 | if let Some(reported) = t.error_reported() { |
95 | return Err(reported); | |
ff7c6d11 XL |
96 | } |
97 | ||
0731742a | 98 | if self.type_is_known_to_be_sized_modulo_regions(t, span) { |
ff7c6d11 | 99 | return Ok(Some(PointerKind::Thin)); |
abe05a73 XL |
100 | } |
101 | ||
1b1a35ee | 102 | Ok(match *t.kind() { |
b7449926 | 103 | ty::Slice(_) | ty::Str => Some(PointerKind::Length), |
dfeec247 XL |
104 | ty::Dynamic(ref tty, ..) => Some(PointerKind::Vtable(tty.principal_def_id())), |
105 | ty::Adt(def, substs) if def.is_struct() => match def.non_enum_variant().fields.last() { | |
106 | None => Some(PointerKind::Thin), | |
107 | Some(f) => { | |
108 | let field_ty = self.field_ty(span, f, substs); | |
109 | self.pointer_kind(field_ty, span)? | |
a7813a04 | 110 | } |
dfeec247 | 111 | }, |
b7449926 | 112 | ty::Tuple(fields) => match fields.last() { |
ff7c6d11 | 113 | None => Some(PointerKind::Thin), |
5e7ed085 | 114 | Some(&f) => self.pointer_kind(f, span)?, |
ff7c6d11 XL |
115 | }, |
116 | ||
abe05a73 | 117 | // Pointers to foreign types are thin, despite being unsized |
b7449926 | 118 | ty::Foreign(..) => Some(PointerKind::Thin), |
a7813a04 | 119 | // We should really try to normalize here. |
b7449926 XL |
120 | ty::Projection(ref pi) => Some(PointerKind::OfProjection(pi)), |
121 | ty::Opaque(def_id, substs) => Some(PointerKind::OfOpaque(def_id, substs)), | |
122 | ty::Param(ref p) => Some(PointerKind::OfParam(p)), | |
abe05a73 | 123 | // Insufficient type information. |
a1dfa0c6 | 124 | ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) => None, |
ff7c6d11 | 125 | |
dfeec247 XL |
126 | ty::Bool |
127 | | ty::Char | |
128 | | ty::Int(..) | |
129 | | ty::Uint(..) | |
130 | | ty::Float(_) | |
131 | | ty::Array(..) | |
132 | | ty::GeneratorWitness(..) | |
133 | | ty::RawPtr(_) | |
134 | | ty::Ref(..) | |
135 | | ty::FnDef(..) | |
136 | | ty::FnPtr(..) | |
137 | | ty::Closure(..) | |
138 | | ty::Generator(..) | |
139 | | ty::Adt(..) | |
140 | | ty::Never | |
f035d41b | 141 | | ty::Error(_) => { |
5e7ed085 FG |
142 | let reported = self |
143 | .tcx | |
dfeec247 XL |
144 | .sess |
145 | .delay_span_bug(span, &format!("`{:?}` should be sized but is not?", t)); | |
5e7ed085 | 146 | return Err(reported); |
ff7c6d11 XL |
147 | } |
148 | }) | |
62682a34 SL |
149 | } |
150 | } | |
151 | ||
152 | #[derive(Copy, Clone)] | |
3dfed10e | 153 | pub enum CastError { |
5e7ed085 | 154 | ErrorGuaranteed, |
ff7c6d11 | 155 | |
62682a34 SL |
156 | CastToBool, |
157 | CastToChar, | |
158 | DifferingKinds, | |
9fa01778 | 159 | /// Cast of thin to fat raw ptr (e.g., `*const () as *const [u8]`). |
54a0048b | 160 | SizedUnsizedCast, |
62682a34 | 161 | IllegalCast, |
476ff2be | 162 | NeedDeref, |
62682a34 | 163 | NeedViaPtr, |
e9174d1e | 164 | NeedViaThinPtr, |
62682a34 | 165 | NeedViaInt, |
62682a34 | 166 | NonScalar, |
abe05a73 XL |
167 | UnknownExprPtrKind, |
168 | UnknownCastPtrKind, | |
5e7ed085 FG |
169 | /// Cast of int to (possibly) fat raw pointer. |
170 | /// | |
171 | /// Argument is the specific name of the metadata in plain words, such as "a vtable" | |
172 | /// or "a length". If this argument is None, then the metadata is unknown, for example, | |
173 | /// when we're typechecking a type parameter with a ?Sized bound. | |
174 | IntToFatCast(Option<&'static str>), | |
62682a34 SL |
175 | } |
176 | ||
5e7ed085 FG |
177 | impl From<ErrorGuaranteed> for CastError { |
178 | fn from(_: ErrorGuaranteed) -> Self { | |
179 | CastError::ErrorGuaranteed | |
ff7c6d11 XL |
180 | } |
181 | } | |
182 | ||
dc9dc135 XL |
183 | fn make_invalid_casting_error<'a, 'tcx>( |
184 | sess: &'a Session, | |
185 | span: Span, | |
186 | expr_ty: Ty<'tcx>, | |
187 | cast_ty: Ty<'tcx>, | |
188 | fcx: &FnCtxt<'a, 'tcx>, | |
5e7ed085 | 189 | ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { |
dfeec247 XL |
190 | type_error_struct!( |
191 | sess, | |
192 | span, | |
193 | expr_ty, | |
194 | E0606, | |
195 | "casting `{}` as `{}` is invalid", | |
196 | fcx.ty_to_string(expr_ty), | |
197 | fcx.ty_to_string(cast_ty) | |
198 | ) | |
041b39d2 XL |
199 | } |
200 | ||
dc9dc135 XL |
201 | impl<'a, 'tcx> CastCheck<'tcx> { |
202 | pub fn new( | |
203 | fcx: &FnCtxt<'a, 'tcx>, | |
dfeec247 | 204 | expr: &'tcx hir::Expr<'tcx>, |
dc9dc135 XL |
205 | expr_ty: Ty<'tcx>, |
206 | cast_ty: Ty<'tcx>, | |
207 | cast_span: Span, | |
208 | span: Span, | |
5e7ed085 | 209 | ) -> Result<CastCheck<'tcx>, ErrorGuaranteed> { |
dfeec247 | 210 | let check = CastCheck { expr, expr_ty, cast_ty, cast_span, span }; |
a7813a04 XL |
211 | |
212 | // For better error messages, check for some obviously unsized | |
213 | // cases now. We do a more thorough check at the end, once | |
214 | // inference is more completely known. | |
1b1a35ee | 215 | match cast_ty.kind() { |
b7449926 | 216 | ty::Dynamic(..) | ty::Slice(..) => { |
5e7ed085 FG |
217 | let reported = check.report_cast_to_unsized_type(fcx); |
218 | Err(reported) | |
a7813a04 | 219 | } |
c30ab7b3 | 220 | _ => Ok(check), |
9346a6ac AL |
221 | } |
222 | } | |
9346a6ac | 223 | |
dc9dc135 | 224 | fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) { |
62682a34 | 225 | match e { |
5e7ed085 | 226 | CastError::ErrorGuaranteed => { |
ff7c6d11 XL |
227 | // an error has already been reported |
228 | } | |
476ff2be | 229 | CastError::NeedDeref => { |
32a655c1 | 230 | let error_span = self.span; |
dfeec247 XL |
231 | let mut err = make_invalid_casting_error( |
232 | fcx.tcx.sess, | |
233 | self.span, | |
234 | self.expr_ty, | |
235 | self.cast_ty, | |
236 | fcx, | |
237 | ); | |
476ff2be | 238 | let cast_ty = fcx.ty_to_string(self.cast_ty); |
dfeec247 XL |
239 | err.span_label( |
240 | error_span, | |
241 | format!("cannot cast `{}` as `{}`", fcx.ty_to_string(self.expr_ty), cast_ty), | |
242 | ); | |
b7449926 | 243 | if let Ok(snippet) = fcx.sess().source_map().span_to_snippet(self.expr.span) { |
9fa01778 | 244 | err.span_suggestion( |
0731742a XL |
245 | self.expr.span, |
246 | "dereference the expression", | |
247 | format!("*{}", snippet), | |
248 | Applicability::MaybeIncorrect, | |
249 | ); | |
250 | } else { | |
251 | err.span_help(self.expr.span, "dereference the expression with `*`"); | |
476ff2be SL |
252 | } |
253 | err.emit(); | |
254 | } | |
dfeec247 XL |
255 | CastError::NeedViaThinPtr | CastError::NeedViaPtr => { |
256 | let mut err = make_invalid_casting_error( | |
257 | fcx.tcx.sess, | |
258 | self.span, | |
259 | self.expr_ty, | |
260 | self.cast_ty, | |
261 | fcx, | |
262 | ); | |
2c00a5a8 | 263 | if self.cast_ty.is_integral() { |
dfeec247 XL |
264 | err.help(&format!( |
265 | "cast through {} first", | |
266 | match e { | |
267 | CastError::NeedViaPtr => "a raw pointer", | |
268 | CastError::NeedViaThinPtr => "a thin pointer", | |
269 | _ => bug!(), | |
270 | } | |
271 | )); | |
476ff2be SL |
272 | } |
273 | err.emit(); | |
274 | } | |
275 | CastError::NeedViaInt => { | |
dfeec247 XL |
276 | make_invalid_casting_error( |
277 | fcx.tcx.sess, | |
278 | self.span, | |
279 | self.expr_ty, | |
280 | self.cast_ty, | |
281 | fcx, | |
282 | ) | |
283 | .help(&format!( | |
284 | "cast through {} first", | |
285 | match e { | |
286 | CastError::NeedViaInt => "an integer", | |
287 | _ => bug!(), | |
288 | } | |
289 | )) | |
290 | .emit(); | |
62682a34 | 291 | } |
041b39d2 | 292 | CastError::IllegalCast => { |
dfeec247 XL |
293 | make_invalid_casting_error( |
294 | fcx.tcx.sess, | |
295 | self.span, | |
296 | self.expr_ty, | |
297 | self.cast_ty, | |
298 | fcx, | |
299 | ) | |
300 | .emit(); | |
041b39d2 XL |
301 | } |
302 | CastError::DifferingKinds => { | |
dfeec247 XL |
303 | make_invalid_casting_error( |
304 | fcx.tcx.sess, | |
305 | self.span, | |
306 | self.expr_ty, | |
307 | self.cast_ty, | |
308 | fcx, | |
309 | ) | |
310 | .note("vtable kinds may not match") | |
311 | .emit(); | |
041b39d2 | 312 | } |
62682a34 | 313 | CastError::CastToBool => { |
0731742a XL |
314 | let mut err = |
315 | struct_span_err!(fcx.tcx.sess, self.span, E0054, "cannot cast as `bool`"); | |
316 | ||
317 | if self.expr_ty.is_numeric() { | |
318 | match fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) { | |
319 | Ok(snippet) => { | |
9fa01778 | 320 | err.span_suggestion( |
0731742a XL |
321 | self.span, |
322 | "compare with zero instead", | |
323 | format!("{} != 0", snippet), | |
324 | Applicability::MachineApplicable, | |
325 | ); | |
326 | } | |
327 | Err(_) => { | |
328 | err.span_help(self.span, "compare with zero instead"); | |
329 | } | |
330 | } | |
331 | } else { | |
332 | err.span_label(self.span, "unsupported cast"); | |
333 | } | |
334 | ||
335 | err.emit(); | |
62682a34 SL |
336 | } |
337 | CastError::CastToChar => { | |
5099ac24 | 338 | let mut err = type_error_struct!( |
dfeec247 XL |
339 | fcx.tcx.sess, |
340 | self.span, | |
341 | self.expr_ty, | |
342 | E0604, | |
343 | "only `u8` can be cast as `char`, not `{}`", | |
344 | self.expr_ty | |
5099ac24 FG |
345 | ); |
346 | err.span_label(self.span, "invalid cast"); | |
347 | if self.expr_ty.is_numeric() { | |
348 | err.span_help( | |
349 | self.span, | |
350 | if self.expr_ty == fcx.tcx.types.i8 { | |
351 | "try casting from `u8` instead" | |
352 | } else if self.expr_ty == fcx.tcx.types.u32 { | |
353 | "try `char::from_u32` instead" | |
354 | } else { | |
355 | "try `char::from_u32` instead (via a `u32`)" | |
356 | }, | |
357 | ); | |
358 | } | |
359 | err.emit(); | |
62682a34 SL |
360 | } |
361 | CastError::NonScalar => { | |
f035d41b | 362 | let mut err = type_error_struct!( |
dfeec247 XL |
363 | fcx.tcx.sess, |
364 | self.span, | |
365 | self.expr_ty, | |
366 | E0605, | |
367 | "non-primitive cast: `{}` as `{}`", | |
368 | self.expr_ty, | |
369 | fcx.ty_to_string(self.cast_ty) | |
f035d41b XL |
370 | ); |
371 | let mut sugg = None; | |
17df50a5 | 372 | let mut sugg_mutref = false; |
c295e0f8 | 373 | if let ty::Ref(reg, cast_ty, mutbl) = *self.cast_ty.kind() { |
17df50a5 XL |
374 | if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind() { |
375 | if fcx | |
376 | .try_coerce( | |
377 | self.expr, | |
378 | fcx.tcx.mk_ref( | |
5099ac24 | 379 | fcx.tcx.lifetimes.re_erased, |
17df50a5 XL |
380 | TypeAndMut { ty: expr_ty, mutbl }, |
381 | ), | |
382 | self.cast_ty, | |
383 | AllowTwoPhase::No, | |
c295e0f8 | 384 | None, |
17df50a5 XL |
385 | ) |
386 | .is_ok() | |
387 | { | |
c295e0f8 | 388 | sugg = Some((format!("&{}*", mutbl.prefix_str()), cast_ty == expr_ty)); |
17df50a5 XL |
389 | } |
390 | } else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind() { | |
391 | if expr_mutbl == Mutability::Not | |
392 | && mutbl == Mutability::Mut | |
393 | && fcx | |
394 | .try_coerce( | |
395 | self.expr, | |
396 | fcx.tcx.mk_ref( | |
397 | expr_reg, | |
398 | TypeAndMut { ty: expr_ty, mutbl: Mutability::Mut }, | |
399 | ), | |
400 | self.cast_ty, | |
401 | AllowTwoPhase::No, | |
c295e0f8 | 402 | None, |
17df50a5 XL |
403 | ) |
404 | .is_ok() | |
405 | { | |
406 | sugg_mutref = true; | |
407 | } | |
408 | } | |
409 | ||
410 | if !sugg_mutref | |
411 | && sugg == None | |
412 | && fcx | |
413 | .try_coerce( | |
414 | self.expr, | |
415 | fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }), | |
416 | self.cast_ty, | |
417 | AllowTwoPhase::No, | |
c295e0f8 | 418 | None, |
17df50a5 XL |
419 | ) |
420 | .is_ok() | |
f035d41b | 421 | { |
c295e0f8 | 422 | sugg = Some((format!("&{}", mutbl.prefix_str()), false)); |
f035d41b | 423 | } |
cdc7bbd5 XL |
424 | } else if let ty::RawPtr(TypeAndMut { mutbl, .. }) = *self.cast_ty.kind() { |
425 | if fcx | |
426 | .try_coerce( | |
427 | self.expr, | |
428 | fcx.tcx.mk_ref( | |
5099ac24 | 429 | fcx.tcx.lifetimes.re_erased, |
cdc7bbd5 XL |
430 | TypeAndMut { ty: self.expr_ty, mutbl }, |
431 | ), | |
432 | self.cast_ty, | |
433 | AllowTwoPhase::No, | |
c295e0f8 | 434 | None, |
cdc7bbd5 XL |
435 | ) |
436 | .is_ok() | |
437 | { | |
c295e0f8 | 438 | sugg = Some((format!("&{}", mutbl.prefix_str()), false)); |
cdc7bbd5 | 439 | } |
f035d41b | 440 | } |
17df50a5 XL |
441 | if sugg_mutref { |
442 | err.span_label(self.span, "invalid cast"); | |
443 | err.span_note(self.expr.span, "this reference is immutable"); | |
444 | err.span_note(self.cast_span, "trying to cast to a mutable reference type"); | |
c295e0f8 | 445 | } else if let Some((sugg, remove_cast)) = sugg { |
f035d41b | 446 | err.span_label(self.span, "invalid cast"); |
c295e0f8 XL |
447 | |
448 | let has_parens = fcx | |
449 | .tcx | |
450 | .sess | |
451 | .source_map() | |
452 | .span_to_snippet(self.expr.span) | |
453 | .map_or(false, |snip| snip.starts_with('(')); | |
454 | ||
455 | // Very crude check to see whether the expression must be wrapped | |
456 | // in parentheses for the suggestion to work (issue #89497). | |
457 | // Can/should be extended in the future. | |
3c0e092e XL |
458 | let needs_parens = |
459 | !has_parens && matches!(self.expr.kind, hir::ExprKind::Cast(..)); | |
c295e0f8 XL |
460 | |
461 | let mut suggestion = vec![(self.expr.span.shrink_to_lo(), sugg)]; | |
462 | if needs_parens { | |
463 | suggestion[0].1 += "("; | |
464 | suggestion.push((self.expr.span.shrink_to_hi(), ")".to_string())); | |
465 | } | |
466 | if remove_cast { | |
467 | suggestion.push(( | |
468 | self.expr.span.shrink_to_hi().to(self.cast_span), | |
469 | String::new(), | |
470 | )); | |
471 | } | |
472 | ||
473 | err.multipart_suggestion_verbose( | |
17df50a5 | 474 | "consider borrowing the value", |
c295e0f8 | 475 | suggestion, |
f035d41b XL |
476 | Applicability::MachineApplicable, |
477 | ); | |
478 | } else if !matches!( | |
1b1a35ee | 479 | self.cast_ty.kind(), |
f035d41b XL |
480 | ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) |
481 | ) { | |
482 | let mut label = true; | |
483 | // Check `impl From<self.expr_ty> for self.cast_ty {}` for accurate suggestion: | |
484 | if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) { | |
c295e0f8 | 485 | if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::From) { |
fc512014 | 486 | let ty = fcx.resolve_vars_if_possible(self.cast_ty); |
f035d41b XL |
487 | // Erase regions to avoid panic in `prove_value` when calling |
488 | // `type_implements_trait`. | |
fc512014 XL |
489 | let ty = fcx.tcx.erase_regions(ty); |
490 | let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); | |
491 | let expr_ty = fcx.tcx.erase_regions(expr_ty); | |
f035d41b | 492 | let ty_params = fcx.tcx.mk_substs_trait(expr_ty, &[]); |
136023e0 XL |
493 | if fcx |
494 | .infcx | |
495 | .type_implements_trait(from_trait, ty, ty_params, fcx.param_env) | |
496 | .must_apply_modulo_regions() | |
f035d41b XL |
497 | { |
498 | label = false; | |
499 | err.span_suggestion( | |
500 | self.span, | |
501 | "consider using the `From` trait instead", | |
502 | format!("{}::from({})", self.cast_ty, snippet), | |
503 | Applicability::MaybeIncorrect, | |
504 | ); | |
505 | } | |
506 | } | |
507 | } | |
508 | let msg = "an `as` expression can only be used to convert between primitive \ | |
509 | types or to coerce to a specific trait object"; | |
510 | if label { | |
511 | err.span_label(self.span, msg); | |
512 | } else { | |
513 | err.note(msg); | |
514 | } | |
515 | } else { | |
516 | err.span_label(self.span, "invalid cast"); | |
517 | } | |
518 | err.emit(); | |
62682a34 | 519 | } |
54a0048b | 520 | CastError::SizedUnsizedCast => { |
5869c6ff XL |
521 | use crate::structured_errors::{SizedUnsizedCast, StructuredDiagnostic}; |
522 | ||
523 | SizedUnsizedCast { | |
524 | sess: &fcx.tcx.sess, | |
525 | span: self.span, | |
526 | expr_ty: self.expr_ty, | |
527 | cast_ty: fcx.ty_to_string(self.cast_ty), | |
528 | } | |
dfeec247 XL |
529 | .diagnostic() |
530 | .emit(); | |
62682a34 | 531 | } |
5e7ed085 FG |
532 | CastError::IntToFatCast(known_metadata) => { |
533 | let mut err = struct_span_err!( | |
534 | fcx.tcx.sess, | |
535 | self.cast_span, | |
536 | E0606, | |
537 | "cannot cast `{}` to a pointer that {} wide", | |
538 | fcx.ty_to_string(self.expr_ty), | |
539 | if known_metadata.is_some() { "is" } else { "may be" } | |
540 | ); | |
541 | ||
542 | err.span_label( | |
543 | self.cast_span, | |
544 | format!( | |
545 | "creating a `{}` requires both an address and {}", | |
546 | self.cast_ty, | |
547 | known_metadata.unwrap_or("type-specific metadata"), | |
548 | ), | |
549 | ); | |
550 | ||
551 | if fcx.tcx.sess.is_nightly_build() { | |
552 | err.span_label( | |
553 | self.expr.span, | |
554 | "consider casting this expression to `*const ()`, \ | |
555 | then using `core::ptr::from_raw_parts`", | |
556 | ); | |
557 | } | |
558 | ||
559 | err.emit(); | |
560 | } | |
dfeec247 | 561 | CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => { |
abe05a73 XL |
562 | let unknown_cast_to = match e { |
563 | CastError::UnknownCastPtrKind => true, | |
564 | CastError::UnknownExprPtrKind => false, | |
565 | _ => bug!(), | |
566 | }; | |
dfeec247 XL |
567 | let mut err = struct_span_err!( |
568 | fcx.tcx.sess, | |
f035d41b | 569 | if unknown_cast_to { self.cast_span } else { self.span }, |
dfeec247 XL |
570 | E0641, |
571 | "cannot cast {} a pointer of an unknown kind", | |
572 | if unknown_cast_to { "to" } else { "from" } | |
573 | ); | |
abe05a73 | 574 | if unknown_cast_to { |
f035d41b XL |
575 | err.span_label(self.cast_span, "needs more type information"); |
576 | err.note( | |
577 | "the type information given here is insufficient to check whether \ | |
578 | the pointer cast is valid", | |
579 | ); | |
580 | } else { | |
581 | err.span_label( | |
582 | self.span, | |
583 | "the type information given here is insufficient to check whether \ | |
584 | the pointer cast is valid", | |
0bf4aa26 | 585 | ); |
abe05a73 XL |
586 | } |
587 | err.emit(); | |
588 | } | |
62682a34 SL |
589 | } |
590 | } | |
591 | ||
5e7ed085 FG |
592 | fn report_cast_to_unsized_type(&self, fcx: &FnCtxt<'a, 'tcx>) -> ErrorGuaranteed { |
593 | if let Some(reported) = | |
594 | self.cast_ty.error_reported().or_else(|| self.expr_ty.error_reported()) | |
595 | { | |
596 | return reported; | |
a7813a04 XL |
597 | } |
598 | ||
599 | let tstr = fcx.ty_to_string(self.cast_ty); | |
dfeec247 XL |
600 | let mut err = type_error_struct!( |
601 | fcx.tcx.sess, | |
602 | self.span, | |
603 | self.expr_ty, | |
604 | E0620, | |
605 | "cast to unsized type: `{}` as `{}`", | |
fc512014 | 606 | fcx.resolve_vars_if_possible(self.expr_ty), |
dfeec247 XL |
607 | tstr |
608 | ); | |
1b1a35ee | 609 | match self.expr_ty.kind() { |
b7449926 | 610 | ty::Ref(_, _, mt) => { |
60c5eb7d | 611 | let mtstr = mt.prefix_str(); |
a7813a04 | 612 | if self.cast_ty.is_trait() { |
b7449926 | 613 | match fcx.tcx.sess.source_map().span_to_snippet(self.cast_span) { |
a7813a04 | 614 | Ok(s) => { |
9fa01778 | 615 | err.span_suggestion( |
0bf4aa26 XL |
616 | self.cast_span, |
617 | "try casting to a reference instead", | |
618 | format!("&{}{}", mtstr, s), | |
619 | Applicability::MachineApplicable, | |
620 | ); | |
c30ab7b3 SL |
621 | } |
622 | Err(_) => { | |
dfeec247 XL |
623 | let msg = &format!("did you mean `&{}{}`?", mtstr, tstr); |
624 | err.span_help(self.cast_span, msg); | |
c30ab7b3 | 625 | } |
a7813a04 XL |
626 | } |
627 | } else { | |
dfeec247 XL |
628 | let msg = &format!( |
629 | "consider using an implicit coercion to `&{}{}` instead", | |
630 | mtstr, tstr | |
631 | ); | |
632 | err.span_help(self.span, msg); | |
a7813a04 XL |
633 | } |
634 | } | |
b7449926 XL |
635 | ty::Adt(def, ..) if def.is_box() => { |
636 | match fcx.tcx.sess.source_map().span_to_snippet(self.cast_span) { | |
a7813a04 | 637 | Ok(s) => { |
9fa01778 | 638 | err.span_suggestion( |
0bf4aa26 | 639 | self.cast_span, |
f035d41b | 640 | "you can cast to a `Box` instead", |
0bf4aa26 XL |
641 | format!("Box<{}>", s), |
642 | Applicability::MachineApplicable, | |
643 | ); | |
c30ab7b3 | 644 | } |
dfeec247 | 645 | Err(_) => { |
f035d41b XL |
646 | err.span_help( |
647 | self.cast_span, | |
648 | &format!("you might have meant `Box<{}>`", tstr), | |
649 | ); | |
dfeec247 | 650 | } |
a7813a04 XL |
651 | } |
652 | } | |
653 | _ => { | |
dfeec247 | 654 | err.span_help(self.expr.span, "consider using a box or reference as appropriate"); |
a7813a04 XL |
655 | } |
656 | } | |
5e7ed085 | 657 | err.emit() |
a7813a04 XL |
658 | } |
659 | ||
dc9dc135 | 660 | fn trivial_cast_lint(&self, fcx: &FnCtxt<'a, 'tcx>) { |
62682a34 SL |
661 | let t_cast = self.cast_ty; |
662 | let t_expr = self.expr_ty; | |
dfeec247 XL |
663 | let type_asc_or = |
664 | if fcx.tcx.features().type_ascription { "type ascription or " } else { "" }; | |
8faf50e0 XL |
665 | let (adjective, lint) = if t_cast.is_numeric() && t_expr.is_numeric() { |
666 | ("numeric ", lint::builtin::TRIVIAL_NUMERIC_CASTS) | |
667 | } else { | |
668 | ("", lint::builtin::TRIVIAL_CASTS) | |
669 | }; | |
74b04a01 XL |
670 | fcx.tcx.struct_span_lint_hir(lint, self.expr.hir_id, self.span, |err| { |
671 | err.build(&format!( | |
dfeec247 XL |
672 | "trivial {}cast: `{}` as `{}`", |
673 | adjective, | |
674 | fcx.ty_to_string(t_expr), | |
675 | fcx.ty_to_string(t_cast) | |
74b04a01 XL |
676 | )) |
677 | .help(&format!( | |
678 | "cast can be replaced by coercion; this might \ | |
679 | require {}a temporary variable", | |
680 | type_asc_or | |
681 | )) | |
682 | .emit(); | |
683 | }); | |
9346a6ac AL |
684 | } |
685 | ||
94222f64 | 686 | #[instrument(skip(fcx), level = "debug")] |
dc9dc135 | 687 | pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) { |
94222f64 XL |
688 | self.expr_ty = fcx.structurally_resolved_type(self.expr.span, self.expr_ty); |
689 | self.cast_ty = fcx.structurally_resolved_type(self.cast_span, self.cast_ty); | |
62682a34 | 690 | |
a2a8927a XL |
691 | debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty); |
692 | ||
693 | if !fcx.type_is_known_to_be_sized_modulo_regions(self.cast_ty, self.span) | |
694 | && !self.cast_ty.has_infer_types() | |
695 | { | |
a7813a04 XL |
696 | self.report_cast_to_unsized_type(fcx); |
697 | } else if self.expr_ty.references_error() || self.cast_ty.references_error() { | |
62682a34 | 698 | // No sense in giving duplicate error messages |
c30ab7b3 | 699 | } else { |
e74abb32 XL |
700 | match self.try_coercion_cast(fcx) { |
701 | Ok(()) => { | |
702 | self.trivial_cast_lint(fcx); | |
703 | debug!(" -> CoercionCast"); | |
3dfed10e | 704 | fcx.typeck_results.borrow_mut().set_coercion_cast(self.expr.hir_id.local_id); |
e74abb32 XL |
705 | } |
706 | Err(ty::error::TypeError::ObjectUnsafeCoercion(did)) => { | |
707 | self.report_object_unsafe_cast(&fcx, did); | |
708 | } | |
709 | Err(_) => { | |
710 | match self.do_check(fcx) { | |
711 | Ok(k) => { | |
712 | debug!(" -> {:?}", k); | |
713 | } | |
714 | Err(e) => self.report_cast_error(fcx, e), | |
715 | }; | |
c30ab7b3 | 716 | } |
c30ab7b3 SL |
717 | }; |
718 | } | |
62682a34 SL |
719 | } |
720 | ||
e74abb32 | 721 | fn report_object_unsafe_cast(&self, fcx: &FnCtxt<'a, 'tcx>, did: DefId) { |
74b04a01 | 722 | let violations = fcx.tcx.object_safety_violations(did); |
dfeec247 | 723 | let mut err = report_object_safety_error(fcx.tcx, self.cast_span, did, violations); |
e74abb32 XL |
724 | err.note(&format!("required by cast to type '{}'", fcx.ty_to_string(self.cast_ty))); |
725 | err.emit(); | |
726 | } | |
727 | ||
9fa01778 | 728 | /// Checks a cast, and report an error if one exists. In some cases, this |
62682a34 SL |
729 | /// can return Ok and create type errors in the fcx rather than returning |
730 | /// directly. coercion-cast is handled in check instead of here. | |
3dfed10e | 731 | pub fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> { |
ba9703b0 XL |
732 | use rustc_middle::ty::cast::CastTy::*; |
733 | use rustc_middle::ty::cast::IntTy::*; | |
62682a34 | 734 | |
dfeec247 XL |
735 | let (t_from, t_cast) = match (CastTy::from_ty(self.expr_ty), CastTy::from_ty(self.cast_ty)) |
736 | { | |
62682a34 | 737 | (Some(t_from), Some(t_cast)) => (t_from, t_cast), |
54a0048b SL |
738 | // Function item types may need to be reified before casts. |
739 | (None, Some(t_cast)) => { | |
1b1a35ee | 740 | match *self.expr_ty.kind() { |
dfeec247 XL |
741 | ty::FnDef(..) => { |
742 | // Attempt a coercion to a fn pointer type. | |
ba9703b0 XL |
743 | let f = fcx.normalize_associated_types_in( |
744 | self.expr.span, | |
fc512014 | 745 | self.expr_ty.fn_sig(fcx.tcx), |
ba9703b0 | 746 | ); |
dfeec247 XL |
747 | let res = fcx.try_coerce( |
748 | self.expr, | |
749 | self.expr_ty, | |
750 | fcx.tcx.mk_fn_ptr(f), | |
751 | AllowTwoPhase::No, | |
c295e0f8 | 752 | None, |
dfeec247 XL |
753 | ); |
754 | if let Err(TypeError::IntrinsicCast) = res { | |
755 | return Err(CastError::IllegalCast); | |
756 | } | |
757 | if res.is_err() { | |
758 | return Err(CastError::NonScalar); | |
759 | } | |
760 | (FnPtr, t_cast) | |
e1599b0c | 761 | } |
dfeec247 XL |
762 | // Special case some errors for references, and check for |
763 | // array-ptr-casts. `Ref` is not a CastTy because the cast | |
764 | // is split into a coercion to a pointer type, followed by | |
765 | // a cast. | |
766 | ty::Ref(_, inner_ty, mutbl) => { | |
767 | return match t_cast { | |
1b1a35ee | 768 | Int(_) | Float => match *inner_ty.kind() { |
dfeec247 XL |
769 | ty::Int(_) |
770 | | ty::Uint(_) | |
771 | | ty::Float(_) | |
ba9703b0 XL |
772 | | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(_)) => { |
773 | Err(CastError::NeedDeref) | |
774 | } | |
dfeec247 XL |
775 | _ => Err(CastError::NeedViaPtr), |
776 | }, | |
777 | // array-ptr-cast | |
778 | Ptr(mt) => { | |
779 | self.check_ref_cast(fcx, TypeAndMut { mutbl, ty: inner_ty }, mt) | |
780 | } | |
781 | _ => Err(CastError::NonScalar), | |
782 | }; | |
54a0048b | 783 | } |
dfeec247 | 784 | _ => return Err(CastError::NonScalar), |
54a0048b SL |
785 | } |
786 | } | |
c30ab7b3 | 787 | _ => return Err(CastError::NonScalar), |
62682a34 SL |
788 | }; |
789 | ||
790 | match (t_from, t_cast) { | |
791 | // These types have invariants! can't cast into them. | |
ba9703b0 | 792 | (_, Int(CEnum) | FnPtr) => Err(CastError::NonScalar), |
62682a34 SL |
793 | |
794 | // * -> Bool | |
795 | (_, Int(Bool)) => Err(CastError::CastToBool), | |
796 | ||
797 | // * -> Char | |
5869c6ff | 798 | (Int(U(ty::UintTy::U8)), Int(Char)) => Ok(CastKind::U8CharCast), // u8-char-cast |
62682a34 SL |
799 | (_, Int(Char)) => Err(CastError::CastToChar), |
800 | ||
801 | // prim -> float,ptr | |
ba9703b0 | 802 | (Int(Bool) | Int(CEnum) | Int(Char), Float) => Err(CastError::NeedViaInt), |
476ff2be | 803 | |
ba9703b0 XL |
804 | (Int(Bool) | Int(CEnum) | Int(Char) | Float, Ptr(_)) | (Ptr(_) | FnPtr, Float) => { |
805 | Err(CastError::IllegalCast) | |
806 | } | |
62682a34 SL |
807 | |
808 | // ptr -> * | |
809 | (Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast | |
810 | (Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast | |
62682a34 | 811 | (FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast), |
dfeec247 | 812 | |
62682a34 SL |
813 | // * -> ptr |
814 | (Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast | |
815 | (FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt), | |
62682a34 SL |
816 | |
817 | // prim -> prim | |
f035d41b XL |
818 | (Int(CEnum), Int(_)) => { |
819 | self.cenum_impl_drop_lint(fcx); | |
820 | Ok(CastKind::EnumCast) | |
821 | } | |
ba9703b0 | 822 | (Int(Char) | Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast), |
62682a34 | 823 | |
ba9703b0 | 824 | (Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast), |
9346a6ac AL |
825 | } |
826 | } | |
827 | ||
dc9dc135 XL |
828 | fn check_ptr_ptr_cast( |
829 | &self, | |
830 | fcx: &FnCtxt<'a, 'tcx>, | |
831 | m_expr: ty::TypeAndMut<'tcx>, | |
832 | m_cast: ty::TypeAndMut<'tcx>, | |
833 | ) -> Result<CastKind, CastError> { | |
c30ab7b3 | 834 | debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", m_expr, m_cast); |
62682a34 SL |
835 | // ptr-ptr cast. vtables must match. |
836 | ||
ff7c6d11 XL |
837 | let expr_kind = fcx.pointer_kind(m_expr.ty, self.span)?; |
838 | let cast_kind = fcx.pointer_kind(m_cast.ty, self.span)?; | |
abe05a73 | 839 | |
5e7ed085 | 840 | let Some(cast_kind) = cast_kind else { |
abe05a73 | 841 | // We can't cast if target pointer kind is unknown |
5e7ed085 | 842 | return Err(CastError::UnknownCastPtrKind); |
abe05a73 XL |
843 | }; |
844 | ||
845 | // Cast to thin pointer is OK | |
846 | if cast_kind == PointerKind::Thin { | |
62682a34 | 847 | return Ok(CastKind::PtrPtrCast); |
9346a6ac | 848 | } |
62682a34 | 849 | |
5e7ed085 | 850 | let Some(expr_kind) = expr_kind else { |
abe05a73 | 851 | // We can't cast to fat pointer if source pointer kind is unknown |
5e7ed085 | 852 | return Err(CastError::UnknownExprPtrKind); |
abe05a73 XL |
853 | }; |
854 | ||
855 | // thin -> fat? report invalid cast (don't complain about vtable kinds) | |
856 | if expr_kind == PointerKind::Thin { | |
54a0048b | 857 | return Err(CastError::SizedUnsizedCast); |
9346a6ac | 858 | } |
9346a6ac | 859 | |
62682a34 | 860 | // vtable kinds must match |
abe05a73 XL |
861 | if cast_kind == expr_kind { |
862 | Ok(CastKind::PtrPtrCast) | |
863 | } else { | |
864 | Err(CastError::DifferingKinds) | |
9346a6ac | 865 | } |
62682a34 | 866 | } |
9346a6ac | 867 | |
dc9dc135 XL |
868 | fn check_fptr_ptr_cast( |
869 | &self, | |
870 | fcx: &FnCtxt<'a, 'tcx>, | |
871 | m_cast: ty::TypeAndMut<'tcx>, | |
872 | ) -> Result<CastKind, CastError> { | |
abe05a73 | 873 | // fptr-ptr cast. must be to thin ptr |
62682a34 | 874 | |
ff7c6d11 | 875 | match fcx.pointer_kind(m_cast.ty, self.span)? { |
abe05a73 XL |
876 | None => Err(CastError::UnknownCastPtrKind), |
877 | Some(PointerKind::Thin) => Ok(CastKind::FnPtrPtrCast), | |
878 | _ => Err(CastError::IllegalCast), | |
62682a34 SL |
879 | } |
880 | } | |
881 | ||
dc9dc135 XL |
882 | fn check_ptr_addr_cast( |
883 | &self, | |
884 | fcx: &FnCtxt<'a, 'tcx>, | |
885 | m_expr: ty::TypeAndMut<'tcx>, | |
886 | ) -> Result<CastKind, CastError> { | |
abe05a73 | 887 | // ptr-addr cast. must be from thin ptr |
62682a34 | 888 | |
ff7c6d11 | 889 | match fcx.pointer_kind(m_expr.ty, self.span)? { |
abe05a73 XL |
890 | None => Err(CastError::UnknownExprPtrKind), |
891 | Some(PointerKind::Thin) => Ok(CastKind::PtrAddrCast), | |
892 | _ => Err(CastError::NeedViaThinPtr), | |
62682a34 SL |
893 | } |
894 | } | |
895 | ||
dc9dc135 XL |
896 | fn check_ref_cast( |
897 | &self, | |
898 | fcx: &FnCtxt<'a, 'tcx>, | |
899 | m_expr: ty::TypeAndMut<'tcx>, | |
900 | m_cast: ty::TypeAndMut<'tcx>, | |
901 | ) -> Result<CastKind, CastError> { | |
6a06907d XL |
902 | // array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const |
903 | if m_expr.mutbl == hir::Mutability::Mut || m_cast.mutbl == hir::Mutability::Not { | |
1b1a35ee | 904 | if let ty::Array(ety, _) = m_expr.ty.kind() { |
62682a34 SL |
905 | // Due to the limitations of LLVM global constants, |
906 | // region pointers end up pointing at copies of | |
907 | // vector elements instead of the original values. | |
908 | // To allow raw pointers to work correctly, we | |
909 | // need to special-case obtaining a raw pointer | |
910 | // from a region pointer to a vector. | |
911 | ||
60c5eb7d XL |
912 | // Coerce to a raw pointer so that we generate AddressOf in MIR. |
913 | let array_ptr_type = fcx.tcx.mk_ptr(m_expr); | |
c295e0f8 | 914 | fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None) |
f035d41b XL |
915 | .unwrap_or_else(|_| { |
916 | bug!( | |
60c5eb7d XL |
917 | "could not cast from reference to array to pointer to array ({:?} to {:?})", |
918 | self.expr_ty, | |
919 | array_ptr_type, | |
f035d41b XL |
920 | ) |
921 | }); | |
60c5eb7d | 922 | |
62682a34 | 923 | // this will report a type mismatch if needed |
5099ac24 | 924 | fcx.demand_eqtype(self.span, *ety, m_cast.ty); |
62682a34 | 925 | return Ok(CastKind::ArrayPtrCast); |
9346a6ac AL |
926 | } |
927 | } | |
62682a34 SL |
928 | |
929 | Err(CastError::IllegalCast) | |
930 | } | |
931 | ||
dc9dc135 XL |
932 | fn check_addr_ptr_cast( |
933 | &self, | |
934 | fcx: &FnCtxt<'a, 'tcx>, | |
935 | m_cast: TypeAndMut<'tcx>, | |
936 | ) -> Result<CastKind, CastError> { | |
62682a34 | 937 | // ptr-addr cast. pointer must be thin. |
ff7c6d11 | 938 | match fcx.pointer_kind(m_cast.ty, self.span)? { |
abe05a73 XL |
939 | None => Err(CastError::UnknownCastPtrKind), |
940 | Some(PointerKind::Thin) => Ok(CastKind::AddrPtrCast), | |
5e7ed085 FG |
941 | Some(PointerKind::Vtable(_)) => Err(CastError::IntToFatCast(Some("a vtable"))), |
942 | Some(PointerKind::Length) => Err(CastError::IntToFatCast(Some("a length"))), | |
943 | Some( | |
944 | PointerKind::OfProjection(_) | |
945 | | PointerKind::OfOpaque(_, _) | |
946 | | PointerKind::OfParam(_), | |
947 | ) => Err(CastError::IntToFatCast(None)), | |
d9579d0f | 948 | } |
9346a6ac | 949 | } |
62682a34 | 950 | |
dfeec247 | 951 | fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<(), ty::error::TypeError<'_>> { |
c295e0f8 | 952 | match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No, None) { |
e74abb32 XL |
953 | Ok(_) => Ok(()), |
954 | Err(err) => Err(err), | |
955 | } | |
62682a34 | 956 | } |
f035d41b XL |
957 | |
958 | fn cenum_impl_drop_lint(&self, fcx: &FnCtxt<'a, 'tcx>) { | |
1b1a35ee | 959 | if let ty::Adt(d, _) = self.expr_ty.kind() { |
f035d41b XL |
960 | if d.has_dtor(fcx.tcx) { |
961 | fcx.tcx.struct_span_lint_hir( | |
962 | lint::builtin::CENUM_IMPL_DROP_CAST, | |
963 | self.expr.hir_id, | |
964 | self.span, | |
965 | |err| { | |
966 | err.build(&format!( | |
967 | "cannot cast enum `{}` into integer `{}` because it implements `Drop`", | |
968 | self.expr_ty, self.cast_ty | |
969 | )) | |
970 | .emit(); | |
971 | }, | |
972 | ); | |
973 | } | |
974 | } | |
975 | } | |
9346a6ac | 976 | } |
a7813a04 | 977 | |
dc9dc135 | 978 | impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
0731742a | 979 | fn type_is_known_to_be_sized_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool { |
3dfed10e | 980 | let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); |
0731742a | 981 | traits::type_known_to_meet_bound_modulo_regions(self, self.param_env, ty, lang_item, span) |
a7813a04 XL |
982 | } |
983 | } |