]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_typeck/src/check/cast.rs
New upstream version 1.61.0+dfsg1
[rustc.git] / compiler / rustc_typeck / src / check / cast.rs
CommitLineData
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 31use super::FnCtxt;
9346a6ac 32
9fa01778 33use crate::hir::def_id::DefId;
dfeec247 34use crate::type_error_struct;
5e7ed085 35use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
dfeec247 36use rustc_hir as hir;
3dfed10e 37use rustc_hir::lang_items::LangItem;
17df50a5 38use rustc_middle::mir::Mutability;
ba9703b0
XL
39use rustc_middle::ty::adjustment::AllowTwoPhase;
40use rustc_middle::ty::cast::{CastKind, CastTy};
41use rustc_middle::ty::error::TypeError;
42use rustc_middle::ty::subst::SubstsRef;
43use rustc_middle::ty::{self, Ty, TypeAndMut, TypeFoldable};
44use rustc_session::lint;
45use rustc_session::Session;
f035d41b 46use rustc_span::symbol::sym;
dfeec247 47use rustc_span::Span;
136023e0 48use rustc_trait_selection::infer::InferCtxtExt;
ba9703b0
XL
49use rustc_trait_selection::traits;
50use 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 55pub 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
67enum 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 82impl<'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 153pub 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
177impl From<ErrorGuaranteed> for CastError {
178 fn from(_: ErrorGuaranteed) -> Self {
179 CastError::ErrorGuaranteed
ff7c6d11
XL
180 }
181}
182
dc9dc135
XL
183fn 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
201impl<'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 978impl<'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}