]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_typeck/src/check/cast.rs
New upstream version 1.58.1+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;
ba9703b0 35use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
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,
89 ) -> Result<Option<PointerKind<'tcx>>, ErrorReported> {
ff7c6d11
XL
90 debug!("pointer_kind({:?}, {:?})", t, span);
91
fc512014 92 let t = self.resolve_vars_if_possible(t);
ff7c6d11
XL
93
94 if t.references_error() {
95 return Err(ErrorReported);
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),
dfeec247 114 Some(f) => self.pointer_kind(f.expect_ty(), 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(_) => {
dfeec247
XL
142 self.tcx
143 .sess
144 .delay_span_bug(span, &format!("`{:?}` should be sized but is not?", t));
ff7c6d11
XL
145 return Err(ErrorReported);
146 }
147 })
62682a34
SL
148 }
149}
150
151#[derive(Copy, Clone)]
3dfed10e 152pub enum CastError {
ff7c6d11
XL
153 ErrorReported,
154
62682a34
SL
155 CastToBool,
156 CastToChar,
157 DifferingKinds,
9fa01778 158 /// Cast of thin to fat raw ptr (e.g., `*const () as *const [u8]`).
54a0048b 159 SizedUnsizedCast,
62682a34 160 IllegalCast,
476ff2be 161 NeedDeref,
62682a34 162 NeedViaPtr,
e9174d1e 163 NeedViaThinPtr,
62682a34 164 NeedViaInt,
62682a34 165 NonScalar,
abe05a73
XL
166 UnknownExprPtrKind,
167 UnknownCastPtrKind,
62682a34
SL
168}
169
ff7c6d11
XL
170impl From<ErrorReported> for CastError {
171 fn from(ErrorReported: ErrorReported) -> Self {
172 CastError::ErrorReported
173 }
174}
175
dc9dc135
XL
176fn make_invalid_casting_error<'a, 'tcx>(
177 sess: &'a Session,
178 span: Span,
179 expr_ty: Ty<'tcx>,
180 cast_ty: Ty<'tcx>,
181 fcx: &FnCtxt<'a, 'tcx>,
182) -> DiagnosticBuilder<'a> {
dfeec247
XL
183 type_error_struct!(
184 sess,
185 span,
186 expr_ty,
187 E0606,
188 "casting `{}` as `{}` is invalid",
189 fcx.ty_to_string(expr_ty),
190 fcx.ty_to_string(cast_ty)
191 )
041b39d2
XL
192}
193
dc9dc135
XL
194impl<'a, 'tcx> CastCheck<'tcx> {
195 pub fn new(
196 fcx: &FnCtxt<'a, 'tcx>,
dfeec247 197 expr: &'tcx hir::Expr<'tcx>,
dc9dc135
XL
198 expr_ty: Ty<'tcx>,
199 cast_ty: Ty<'tcx>,
200 cast_span: Span,
201 span: Span,
202 ) -> Result<CastCheck<'tcx>, ErrorReported> {
dfeec247 203 let check = CastCheck { expr, expr_ty, cast_ty, cast_span, span };
a7813a04
XL
204
205 // For better error messages, check for some obviously unsized
206 // cases now. We do a more thorough check at the end, once
207 // inference is more completely known.
1b1a35ee 208 match cast_ty.kind() {
b7449926 209 ty::Dynamic(..) | ty::Slice(..) => {
a7813a04
XL
210 check.report_cast_to_unsized_type(fcx);
211 Err(ErrorReported)
212 }
c30ab7b3 213 _ => Ok(check),
9346a6ac
AL
214 }
215 }
9346a6ac 216
dc9dc135 217 fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
62682a34 218 match e {
ff7c6d11
XL
219 CastError::ErrorReported => {
220 // an error has already been reported
221 }
476ff2be 222 CastError::NeedDeref => {
32a655c1 223 let error_span = self.span;
dfeec247
XL
224 let mut err = make_invalid_casting_error(
225 fcx.tcx.sess,
226 self.span,
227 self.expr_ty,
228 self.cast_ty,
229 fcx,
230 );
476ff2be 231 let cast_ty = fcx.ty_to_string(self.cast_ty);
dfeec247
XL
232 err.span_label(
233 error_span,
234 format!("cannot cast `{}` as `{}`", fcx.ty_to_string(self.expr_ty), cast_ty),
235 );
b7449926 236 if let Ok(snippet) = fcx.sess().source_map().span_to_snippet(self.expr.span) {
9fa01778 237 err.span_suggestion(
0731742a
XL
238 self.expr.span,
239 "dereference the expression",
240 format!("*{}", snippet),
241 Applicability::MaybeIncorrect,
242 );
243 } else {
244 err.span_help(self.expr.span, "dereference the expression with `*`");
476ff2be
SL
245 }
246 err.emit();
247 }
dfeec247
XL
248 CastError::NeedViaThinPtr | CastError::NeedViaPtr => {
249 let mut err = make_invalid_casting_error(
250 fcx.tcx.sess,
251 self.span,
252 self.expr_ty,
253 self.cast_ty,
254 fcx,
255 );
2c00a5a8 256 if self.cast_ty.is_integral() {
dfeec247
XL
257 err.help(&format!(
258 "cast through {} first",
259 match e {
260 CastError::NeedViaPtr => "a raw pointer",
261 CastError::NeedViaThinPtr => "a thin pointer",
262 _ => bug!(),
263 }
264 ));
476ff2be
SL
265 }
266 err.emit();
267 }
268 CastError::NeedViaInt => {
dfeec247
XL
269 make_invalid_casting_error(
270 fcx.tcx.sess,
271 self.span,
272 self.expr_ty,
273 self.cast_ty,
274 fcx,
275 )
276 .help(&format!(
277 "cast through {} first",
278 match e {
279 CastError::NeedViaInt => "an integer",
280 _ => bug!(),
281 }
282 ))
283 .emit();
62682a34 284 }
041b39d2 285 CastError::IllegalCast => {
dfeec247
XL
286 make_invalid_casting_error(
287 fcx.tcx.sess,
288 self.span,
289 self.expr_ty,
290 self.cast_ty,
291 fcx,
292 )
293 .emit();
041b39d2
XL
294 }
295 CastError::DifferingKinds => {
dfeec247
XL
296 make_invalid_casting_error(
297 fcx.tcx.sess,
298 self.span,
299 self.expr_ty,
300 self.cast_ty,
301 fcx,
302 )
303 .note("vtable kinds may not match")
304 .emit();
041b39d2 305 }
62682a34 306 CastError::CastToBool => {
0731742a
XL
307 let mut err =
308 struct_span_err!(fcx.tcx.sess, self.span, E0054, "cannot cast as `bool`");
309
310 if self.expr_ty.is_numeric() {
311 match fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
312 Ok(snippet) => {
9fa01778 313 err.span_suggestion(
0731742a
XL
314 self.span,
315 "compare with zero instead",
316 format!("{} != 0", snippet),
317 Applicability::MachineApplicable,
318 );
319 }
320 Err(_) => {
321 err.span_help(self.span, "compare with zero instead");
322 }
323 }
324 } else {
325 err.span_label(self.span, "unsupported cast");
326 }
327
328 err.emit();
62682a34
SL
329 }
330 CastError::CastToChar => {
dfeec247
XL
331 type_error_struct!(
332 fcx.tcx.sess,
333 self.span,
334 self.expr_ty,
335 E0604,
336 "only `u8` can be cast as `char`, not `{}`",
337 self.expr_ty
338 )
f035d41b 339 .span_label(self.span, "invalid cast")
dfeec247 340 .emit();
62682a34
SL
341 }
342 CastError::NonScalar => {
f035d41b 343 let mut err = type_error_struct!(
dfeec247
XL
344 fcx.tcx.sess,
345 self.span,
346 self.expr_ty,
347 E0605,
348 "non-primitive cast: `{}` as `{}`",
349 self.expr_ty,
350 fcx.ty_to_string(self.cast_ty)
f035d41b
XL
351 );
352 let mut sugg = None;
17df50a5 353 let mut sugg_mutref = false;
c295e0f8 354 if let ty::Ref(reg, cast_ty, mutbl) = *self.cast_ty.kind() {
17df50a5
XL
355 if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind() {
356 if fcx
357 .try_coerce(
358 self.expr,
359 fcx.tcx.mk_ref(
360 &ty::RegionKind::ReErased,
361 TypeAndMut { ty: expr_ty, mutbl },
362 ),
363 self.cast_ty,
364 AllowTwoPhase::No,
c295e0f8 365 None,
17df50a5
XL
366 )
367 .is_ok()
368 {
c295e0f8 369 sugg = Some((format!("&{}*", mutbl.prefix_str()), cast_ty == expr_ty));
17df50a5
XL
370 }
371 } else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind() {
372 if expr_mutbl == Mutability::Not
373 && mutbl == Mutability::Mut
374 && fcx
375 .try_coerce(
376 self.expr,
377 fcx.tcx.mk_ref(
378 expr_reg,
379 TypeAndMut { ty: expr_ty, mutbl: Mutability::Mut },
380 ),
381 self.cast_ty,
382 AllowTwoPhase::No,
c295e0f8 383 None,
17df50a5
XL
384 )
385 .is_ok()
386 {
387 sugg_mutref = true;
388 }
389 }
390
391 if !sugg_mutref
392 && sugg == None
393 && fcx
394 .try_coerce(
395 self.expr,
396 fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }),
397 self.cast_ty,
398 AllowTwoPhase::No,
c295e0f8 399 None,
17df50a5
XL
400 )
401 .is_ok()
f035d41b 402 {
c295e0f8 403 sugg = Some((format!("&{}", mutbl.prefix_str()), false));
f035d41b 404 }
cdc7bbd5
XL
405 } else if let ty::RawPtr(TypeAndMut { mutbl, .. }) = *self.cast_ty.kind() {
406 if fcx
407 .try_coerce(
408 self.expr,
409 fcx.tcx.mk_ref(
410 &ty::RegionKind::ReErased,
411 TypeAndMut { ty: self.expr_ty, mutbl },
412 ),
413 self.cast_ty,
414 AllowTwoPhase::No,
c295e0f8 415 None,
cdc7bbd5
XL
416 )
417 .is_ok()
418 {
c295e0f8 419 sugg = Some((format!("&{}", mutbl.prefix_str()), false));
cdc7bbd5 420 }
f035d41b 421 }
17df50a5
XL
422 if sugg_mutref {
423 err.span_label(self.span, "invalid cast");
424 err.span_note(self.expr.span, "this reference is immutable");
425 err.span_note(self.cast_span, "trying to cast to a mutable reference type");
c295e0f8 426 } else if let Some((sugg, remove_cast)) = sugg {
f035d41b 427 err.span_label(self.span, "invalid cast");
c295e0f8
XL
428
429 let has_parens = fcx
430 .tcx
431 .sess
432 .source_map()
433 .span_to_snippet(self.expr.span)
434 .map_or(false, |snip| snip.starts_with('('));
435
436 // Very crude check to see whether the expression must be wrapped
437 // in parentheses for the suggestion to work (issue #89497).
438 // Can/should be extended in the future.
3c0e092e
XL
439 let needs_parens =
440 !has_parens && matches!(self.expr.kind, hir::ExprKind::Cast(..));
c295e0f8
XL
441
442 let mut suggestion = vec![(self.expr.span.shrink_to_lo(), sugg)];
443 if needs_parens {
444 suggestion[0].1 += "(";
445 suggestion.push((self.expr.span.shrink_to_hi(), ")".to_string()));
446 }
447 if remove_cast {
448 suggestion.push((
449 self.expr.span.shrink_to_hi().to(self.cast_span),
450 String::new(),
451 ));
452 }
453
454 err.multipart_suggestion_verbose(
17df50a5 455 "consider borrowing the value",
c295e0f8 456 suggestion,
f035d41b
XL
457 Applicability::MachineApplicable,
458 );
459 } else if !matches!(
1b1a35ee 460 self.cast_ty.kind(),
f035d41b
XL
461 ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..)
462 ) {
463 let mut label = true;
464 // Check `impl From<self.expr_ty> for self.cast_ty {}` for accurate suggestion:
465 if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
c295e0f8 466 if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::From) {
fc512014 467 let ty = fcx.resolve_vars_if_possible(self.cast_ty);
f035d41b
XL
468 // Erase regions to avoid panic in `prove_value` when calling
469 // `type_implements_trait`.
fc512014
XL
470 let ty = fcx.tcx.erase_regions(ty);
471 let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
472 let expr_ty = fcx.tcx.erase_regions(expr_ty);
f035d41b 473 let ty_params = fcx.tcx.mk_substs_trait(expr_ty, &[]);
136023e0
XL
474 if fcx
475 .infcx
476 .type_implements_trait(from_trait, ty, ty_params, fcx.param_env)
477 .must_apply_modulo_regions()
f035d41b
XL
478 {
479 label = false;
480 err.span_suggestion(
481 self.span,
482 "consider using the `From` trait instead",
483 format!("{}::from({})", self.cast_ty, snippet),
484 Applicability::MaybeIncorrect,
485 );
486 }
487 }
488 }
489 let msg = "an `as` expression can only be used to convert between primitive \
490 types or to coerce to a specific trait object";
491 if label {
492 err.span_label(self.span, msg);
493 } else {
494 err.note(msg);
495 }
496 } else {
497 err.span_label(self.span, "invalid cast");
498 }
499 err.emit();
62682a34 500 }
54a0048b 501 CastError::SizedUnsizedCast => {
5869c6ff
XL
502 use crate::structured_errors::{SizedUnsizedCast, StructuredDiagnostic};
503
504 SizedUnsizedCast {
505 sess: &fcx.tcx.sess,
506 span: self.span,
507 expr_ty: self.expr_ty,
508 cast_ty: fcx.ty_to_string(self.cast_ty),
509 }
dfeec247
XL
510 .diagnostic()
511 .emit();
62682a34 512 }
dfeec247 513 CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => {
abe05a73
XL
514 let unknown_cast_to = match e {
515 CastError::UnknownCastPtrKind => true,
516 CastError::UnknownExprPtrKind => false,
517 _ => bug!(),
518 };
dfeec247
XL
519 let mut err = struct_span_err!(
520 fcx.tcx.sess,
f035d41b 521 if unknown_cast_to { self.cast_span } else { self.span },
dfeec247
XL
522 E0641,
523 "cannot cast {} a pointer of an unknown kind",
524 if unknown_cast_to { "to" } else { "from" }
525 );
abe05a73 526 if unknown_cast_to {
f035d41b
XL
527 err.span_label(self.cast_span, "needs more type information");
528 err.note(
529 "the type information given here is insufficient to check whether \
530 the pointer cast is valid",
531 );
532 } else {
533 err.span_label(
534 self.span,
535 "the type information given here is insufficient to check whether \
536 the pointer cast is valid",
0bf4aa26 537 );
abe05a73
XL
538 }
539 err.emit();
540 }
62682a34
SL
541 }
542 }
543
dc9dc135 544 fn report_cast_to_unsized_type(&self, fcx: &FnCtxt<'a, 'tcx>) {
c30ab7b3 545 if self.cast_ty.references_error() || self.expr_ty.references_error() {
a7813a04
XL
546 return;
547 }
548
549 let tstr = fcx.ty_to_string(self.cast_ty);
dfeec247
XL
550 let mut err = type_error_struct!(
551 fcx.tcx.sess,
552 self.span,
553 self.expr_ty,
554 E0620,
555 "cast to unsized type: `{}` as `{}`",
fc512014 556 fcx.resolve_vars_if_possible(self.expr_ty),
dfeec247
XL
557 tstr
558 );
1b1a35ee 559 match self.expr_ty.kind() {
b7449926 560 ty::Ref(_, _, mt) => {
60c5eb7d 561 let mtstr = mt.prefix_str();
a7813a04 562 if self.cast_ty.is_trait() {
b7449926 563 match fcx.tcx.sess.source_map().span_to_snippet(self.cast_span) {
a7813a04 564 Ok(s) => {
9fa01778 565 err.span_suggestion(
0bf4aa26
XL
566 self.cast_span,
567 "try casting to a reference instead",
568 format!("&{}{}", mtstr, s),
569 Applicability::MachineApplicable,
570 );
c30ab7b3
SL
571 }
572 Err(_) => {
dfeec247
XL
573 let msg = &format!("did you mean `&{}{}`?", mtstr, tstr);
574 err.span_help(self.cast_span, msg);
c30ab7b3 575 }
a7813a04
XL
576 }
577 } else {
dfeec247
XL
578 let msg = &format!(
579 "consider using an implicit coercion to `&{}{}` instead",
580 mtstr, tstr
581 );
582 err.span_help(self.span, msg);
a7813a04
XL
583 }
584 }
b7449926
XL
585 ty::Adt(def, ..) if def.is_box() => {
586 match fcx.tcx.sess.source_map().span_to_snippet(self.cast_span) {
a7813a04 587 Ok(s) => {
9fa01778 588 err.span_suggestion(
0bf4aa26 589 self.cast_span,
f035d41b 590 "you can cast to a `Box` instead",
0bf4aa26
XL
591 format!("Box<{}>", s),
592 Applicability::MachineApplicable,
593 );
c30ab7b3 594 }
dfeec247 595 Err(_) => {
f035d41b
XL
596 err.span_help(
597 self.cast_span,
598 &format!("you might have meant `Box<{}>`", tstr),
599 );
dfeec247 600 }
a7813a04
XL
601 }
602 }
603 _ => {
dfeec247 604 err.span_help(self.expr.span, "consider using a box or reference as appropriate");
a7813a04
XL
605 }
606 }
607 err.emit();
608 }
609
dc9dc135 610 fn trivial_cast_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
62682a34
SL
611 let t_cast = self.cast_ty;
612 let t_expr = self.expr_ty;
dfeec247
XL
613 let type_asc_or =
614 if fcx.tcx.features().type_ascription { "type ascription or " } else { "" };
8faf50e0
XL
615 let (adjective, lint) = if t_cast.is_numeric() && t_expr.is_numeric() {
616 ("numeric ", lint::builtin::TRIVIAL_NUMERIC_CASTS)
617 } else {
618 ("", lint::builtin::TRIVIAL_CASTS)
619 };
74b04a01
XL
620 fcx.tcx.struct_span_lint_hir(lint, self.expr.hir_id, self.span, |err| {
621 err.build(&format!(
dfeec247
XL
622 "trivial {}cast: `{}` as `{}`",
623 adjective,
624 fcx.ty_to_string(t_expr),
625 fcx.ty_to_string(t_cast)
74b04a01
XL
626 ))
627 .help(&format!(
628 "cast can be replaced by coercion; this might \
629 require {}a temporary variable",
630 type_asc_or
631 ))
632 .emit();
633 });
9346a6ac
AL
634 }
635
94222f64 636 #[instrument(skip(fcx), level = "debug")]
dc9dc135 637 pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) {
94222f64
XL
638 self.expr_ty = fcx.structurally_resolved_type(self.expr.span, self.expr_ty);
639 self.cast_ty = fcx.structurally_resolved_type(self.cast_span, self.cast_ty);
62682a34 640
0731742a 641 if !fcx.type_is_known_to_be_sized_modulo_regions(self.cast_ty, self.span) {
a7813a04
XL
642 self.report_cast_to_unsized_type(fcx);
643 } else if self.expr_ty.references_error() || self.cast_ty.references_error() {
62682a34 644 // No sense in giving duplicate error messages
c30ab7b3 645 } else {
e74abb32
XL
646 match self.try_coercion_cast(fcx) {
647 Ok(()) => {
648 self.trivial_cast_lint(fcx);
649 debug!(" -> CoercionCast");
3dfed10e 650 fcx.typeck_results.borrow_mut().set_coercion_cast(self.expr.hir_id.local_id);
e74abb32
XL
651 }
652 Err(ty::error::TypeError::ObjectUnsafeCoercion(did)) => {
653 self.report_object_unsafe_cast(&fcx, did);
654 }
655 Err(_) => {
656 match self.do_check(fcx) {
657 Ok(k) => {
658 debug!(" -> {:?}", k);
659 }
660 Err(e) => self.report_cast_error(fcx, e),
661 };
c30ab7b3 662 }
c30ab7b3
SL
663 };
664 }
62682a34
SL
665 }
666
e74abb32 667 fn report_object_unsafe_cast(&self, fcx: &FnCtxt<'a, 'tcx>, did: DefId) {
74b04a01 668 let violations = fcx.tcx.object_safety_violations(did);
dfeec247 669 let mut err = report_object_safety_error(fcx.tcx, self.cast_span, did, violations);
e74abb32
XL
670 err.note(&format!("required by cast to type '{}'", fcx.ty_to_string(self.cast_ty)));
671 err.emit();
672 }
673
9fa01778 674 /// Checks a cast, and report an error if one exists. In some cases, this
62682a34
SL
675 /// can return Ok and create type errors in the fcx rather than returning
676 /// directly. coercion-cast is handled in check instead of here.
3dfed10e 677 pub fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
ba9703b0
XL
678 use rustc_middle::ty::cast::CastTy::*;
679 use rustc_middle::ty::cast::IntTy::*;
62682a34 680
dfeec247
XL
681 let (t_from, t_cast) = match (CastTy::from_ty(self.expr_ty), CastTy::from_ty(self.cast_ty))
682 {
62682a34 683 (Some(t_from), Some(t_cast)) => (t_from, t_cast),
54a0048b
SL
684 // Function item types may need to be reified before casts.
685 (None, Some(t_cast)) => {
1b1a35ee 686 match *self.expr_ty.kind() {
dfeec247
XL
687 ty::FnDef(..) => {
688 // Attempt a coercion to a fn pointer type.
ba9703b0
XL
689 let f = fcx.normalize_associated_types_in(
690 self.expr.span,
fc512014 691 self.expr_ty.fn_sig(fcx.tcx),
ba9703b0 692 );
dfeec247
XL
693 let res = fcx.try_coerce(
694 self.expr,
695 self.expr_ty,
696 fcx.tcx.mk_fn_ptr(f),
697 AllowTwoPhase::No,
c295e0f8 698 None,
dfeec247
XL
699 );
700 if let Err(TypeError::IntrinsicCast) = res {
701 return Err(CastError::IllegalCast);
702 }
703 if res.is_err() {
704 return Err(CastError::NonScalar);
705 }
706 (FnPtr, t_cast)
e1599b0c 707 }
dfeec247
XL
708 // Special case some errors for references, and check for
709 // array-ptr-casts. `Ref` is not a CastTy because the cast
710 // is split into a coercion to a pointer type, followed by
711 // a cast.
712 ty::Ref(_, inner_ty, mutbl) => {
713 return match t_cast {
1b1a35ee 714 Int(_) | Float => match *inner_ty.kind() {
dfeec247
XL
715 ty::Int(_)
716 | ty::Uint(_)
717 | ty::Float(_)
ba9703b0
XL
718 | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(_)) => {
719 Err(CastError::NeedDeref)
720 }
dfeec247
XL
721 _ => Err(CastError::NeedViaPtr),
722 },
723 // array-ptr-cast
724 Ptr(mt) => {
725 self.check_ref_cast(fcx, TypeAndMut { mutbl, ty: inner_ty }, mt)
726 }
727 _ => Err(CastError::NonScalar),
728 };
54a0048b 729 }
dfeec247 730 _ => return Err(CastError::NonScalar),
54a0048b
SL
731 }
732 }
c30ab7b3 733 _ => return Err(CastError::NonScalar),
62682a34
SL
734 };
735
736 match (t_from, t_cast) {
737 // These types have invariants! can't cast into them.
ba9703b0 738 (_, Int(CEnum) | FnPtr) => Err(CastError::NonScalar),
62682a34
SL
739
740 // * -> Bool
741 (_, Int(Bool)) => Err(CastError::CastToBool),
742
743 // * -> Char
5869c6ff 744 (Int(U(ty::UintTy::U8)), Int(Char)) => Ok(CastKind::U8CharCast), // u8-char-cast
62682a34
SL
745 (_, Int(Char)) => Err(CastError::CastToChar),
746
747 // prim -> float,ptr
ba9703b0 748 (Int(Bool) | Int(CEnum) | Int(Char), Float) => Err(CastError::NeedViaInt),
476ff2be 749
ba9703b0
XL
750 (Int(Bool) | Int(CEnum) | Int(Char) | Float, Ptr(_)) | (Ptr(_) | FnPtr, Float) => {
751 Err(CastError::IllegalCast)
752 }
62682a34
SL
753
754 // ptr -> *
755 (Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
756 (Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast
62682a34 757 (FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast),
dfeec247 758
62682a34
SL
759 // * -> ptr
760 (Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast
761 (FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
62682a34
SL
762
763 // prim -> prim
f035d41b
XL
764 (Int(CEnum), Int(_)) => {
765 self.cenum_impl_drop_lint(fcx);
766 Ok(CastKind::EnumCast)
767 }
ba9703b0 768 (Int(Char) | Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast),
62682a34 769
ba9703b0 770 (Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast),
9346a6ac
AL
771 }
772 }
773
dc9dc135
XL
774 fn check_ptr_ptr_cast(
775 &self,
776 fcx: &FnCtxt<'a, 'tcx>,
777 m_expr: ty::TypeAndMut<'tcx>,
778 m_cast: ty::TypeAndMut<'tcx>,
779 ) -> Result<CastKind, CastError> {
c30ab7b3 780 debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", m_expr, m_cast);
62682a34
SL
781 // ptr-ptr cast. vtables must match.
782
ff7c6d11
XL
783 let expr_kind = fcx.pointer_kind(m_expr.ty, self.span)?;
784 let cast_kind = fcx.pointer_kind(m_cast.ty, self.span)?;
abe05a73
XL
785
786 let cast_kind = match cast_kind {
787 // We can't cast if target pointer kind is unknown
788 None => return Err(CastError::UnknownCastPtrKind),
789 Some(cast_kind) => cast_kind,
790 };
791
792 // Cast to thin pointer is OK
793 if cast_kind == PointerKind::Thin {
62682a34 794 return Ok(CastKind::PtrPtrCast);
9346a6ac 795 }
62682a34 796
abe05a73
XL
797 let expr_kind = match expr_kind {
798 // We can't cast to fat pointer if source pointer kind is unknown
799 None => return Err(CastError::UnknownExprPtrKind),
800 Some(expr_kind) => expr_kind,
801 };
802
803 // thin -> fat? report invalid cast (don't complain about vtable kinds)
804 if expr_kind == PointerKind::Thin {
54a0048b 805 return Err(CastError::SizedUnsizedCast);
9346a6ac 806 }
9346a6ac 807
62682a34 808 // vtable kinds must match
abe05a73
XL
809 if cast_kind == expr_kind {
810 Ok(CastKind::PtrPtrCast)
811 } else {
812 Err(CastError::DifferingKinds)
9346a6ac 813 }
62682a34 814 }
9346a6ac 815
dc9dc135
XL
816 fn check_fptr_ptr_cast(
817 &self,
818 fcx: &FnCtxt<'a, 'tcx>,
819 m_cast: ty::TypeAndMut<'tcx>,
820 ) -> Result<CastKind, CastError> {
abe05a73 821 // fptr-ptr cast. must be to thin ptr
62682a34 822
ff7c6d11 823 match fcx.pointer_kind(m_cast.ty, self.span)? {
abe05a73
XL
824 None => Err(CastError::UnknownCastPtrKind),
825 Some(PointerKind::Thin) => Ok(CastKind::FnPtrPtrCast),
826 _ => Err(CastError::IllegalCast),
62682a34
SL
827 }
828 }
829
dc9dc135
XL
830 fn check_ptr_addr_cast(
831 &self,
832 fcx: &FnCtxt<'a, 'tcx>,
833 m_expr: ty::TypeAndMut<'tcx>,
834 ) -> Result<CastKind, CastError> {
abe05a73 835 // ptr-addr cast. must be from thin ptr
62682a34 836
ff7c6d11 837 match fcx.pointer_kind(m_expr.ty, self.span)? {
abe05a73
XL
838 None => Err(CastError::UnknownExprPtrKind),
839 Some(PointerKind::Thin) => Ok(CastKind::PtrAddrCast),
840 _ => Err(CastError::NeedViaThinPtr),
62682a34
SL
841 }
842 }
843
dc9dc135
XL
844 fn check_ref_cast(
845 &self,
846 fcx: &FnCtxt<'a, 'tcx>,
847 m_expr: ty::TypeAndMut<'tcx>,
848 m_cast: ty::TypeAndMut<'tcx>,
849 ) -> Result<CastKind, CastError> {
6a06907d
XL
850 // array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const
851 if m_expr.mutbl == hir::Mutability::Mut || m_cast.mutbl == hir::Mutability::Not {
1b1a35ee 852 if let ty::Array(ety, _) = m_expr.ty.kind() {
62682a34
SL
853 // Due to the limitations of LLVM global constants,
854 // region pointers end up pointing at copies of
855 // vector elements instead of the original values.
856 // To allow raw pointers to work correctly, we
857 // need to special-case obtaining a raw pointer
858 // from a region pointer to a vector.
859
60c5eb7d
XL
860 // Coerce to a raw pointer so that we generate AddressOf in MIR.
861 let array_ptr_type = fcx.tcx.mk_ptr(m_expr);
c295e0f8 862 fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None)
f035d41b
XL
863 .unwrap_or_else(|_| {
864 bug!(
60c5eb7d
XL
865 "could not cast from reference to array to pointer to array ({:?} to {:?})",
866 self.expr_ty,
867 array_ptr_type,
f035d41b
XL
868 )
869 });
60c5eb7d 870
62682a34 871 // this will report a type mismatch if needed
a7813a04 872 fcx.demand_eqtype(self.span, ety, m_cast.ty);
62682a34 873 return Ok(CastKind::ArrayPtrCast);
9346a6ac
AL
874 }
875 }
62682a34
SL
876
877 Err(CastError::IllegalCast)
878 }
879
dc9dc135
XL
880 fn check_addr_ptr_cast(
881 &self,
882 fcx: &FnCtxt<'a, 'tcx>,
883 m_cast: TypeAndMut<'tcx>,
884 ) -> Result<CastKind, CastError> {
62682a34 885 // ptr-addr cast. pointer must be thin.
ff7c6d11 886 match fcx.pointer_kind(m_cast.ty, self.span)? {
abe05a73
XL
887 None => Err(CastError::UnknownCastPtrKind),
888 Some(PointerKind::Thin) => Ok(CastKind::AddrPtrCast),
889 _ => Err(CastError::IllegalCast),
d9579d0f 890 }
9346a6ac 891 }
62682a34 892
dfeec247 893 fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<(), ty::error::TypeError<'_>> {
c295e0f8 894 match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No, None) {
e74abb32
XL
895 Ok(_) => Ok(()),
896 Err(err) => Err(err),
897 }
62682a34 898 }
f035d41b
XL
899
900 fn cenum_impl_drop_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
1b1a35ee 901 if let ty::Adt(d, _) = self.expr_ty.kind() {
f035d41b
XL
902 if d.has_dtor(fcx.tcx) {
903 fcx.tcx.struct_span_lint_hir(
904 lint::builtin::CENUM_IMPL_DROP_CAST,
905 self.expr.hir_id,
906 self.span,
907 |err| {
908 err.build(&format!(
909 "cannot cast enum `{}` into integer `{}` because it implements `Drop`",
910 self.expr_ty, self.cast_ty
911 ))
912 .emit();
913 },
914 );
915 }
916 }
917 }
9346a6ac 918}
a7813a04 919
dc9dc135 920impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
0731742a 921 fn type_is_known_to_be_sized_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool {
3dfed10e 922 let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
0731742a 923 traits::type_known_to_meet_bound_modulo_regions(self, self.param_env, ty, lang_item, span)
a7813a04
XL
924 }
925}