]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_hir_typeck/src/cast.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / compiler / rustc_hir_typeck / src / 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
dfeec247 33use crate::type_error_struct;
f25598a0
FG
34use hir::ExprKind;
35use rustc_errors::{
36 struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
37};
dfeec247 38use rustc_hir as hir;
487cf647 39use rustc_macros::{TypeFoldable, TypeVisitable};
17df50a5 40use rustc_middle::mir::Mutability;
ba9703b0
XL
41use rustc_middle::ty::adjustment::AllowTwoPhase;
42use rustc_middle::ty::cast::{CastKind, CastTy};
43use rustc_middle::ty::error::TypeError;
2b03887a 44use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef};
ba9703b0
XL
45use rustc_session::lint;
46use rustc_session::Session;
2b03887a 47use rustc_span::def_id::{DefId, LOCAL_CRATE};
f035d41b 48use rustc_span::symbol::sym;
dfeec247 49use rustc_span::Span;
136023e0 50use rustc_trait_selection::infer::InferCtxtExt;
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> {
f2b60f7d 56 /// The expression whose value is being casted
dfeec247 57 expr: &'tcx hir::Expr<'tcx>,
f2b60f7d 58 /// The source type for the cast expression
9346a6ac 59 expr_ty: Ty<'tcx>,
04454e1e 60 expr_span: Span,
f2b60f7d 61 /// The target type. That is, the type we are casting to.
9346a6ac 62 cast_ty: Ty<'tcx>,
a7813a04 63 cast_span: Span,
9346a6ac 64 span: Span,
2b03887a
FG
65 /// whether the cast is made in a const context or not.
66 pub constness: hir::Constness,
9346a6ac
AL
67}
68
abe05a73
XL
69/// The kind of pointer and associated metadata (thin, length or vtable) - we
70/// only allow casts between fat pointers if their metadata have the same
71/// kind.
487cf647 72#[derive(Debug, Copy, Clone, PartialEq, Eq, TypeVisitable, TypeFoldable)]
abe05a73
XL
73enum PointerKind<'tcx> {
74 /// No metadata attached, ie pointer to sized type or foreign type
75 Thin,
76 /// A trait object
064997fb 77 VTable(Option<DefId>),
abe05a73 78 /// Slice
62682a34 79 Length,
f25598a0
FG
80 /// The unsize info of this projection or opaque type
81 OfAlias(ty::AliasTy<'tcx>),
62682a34 82 /// The unsize info of this parameter
487cf647 83 OfParam(ty::ParamTy),
62682a34
SL
84}
85
dc9dc135 86impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
a7813a04 87 /// Returns the kind of unsize information of t, or None
abe05a73 88 /// if t is unknown.
dfeec247
XL
89 fn pointer_kind(
90 &self,
91 t: Ty<'tcx>,
92 span: Span,
5e7ed085 93 ) -> Result<Option<PointerKind<'tcx>>, ErrorGuaranteed> {
ff7c6d11
XL
94 debug!("pointer_kind({:?}, {:?})", t, span);
95
fc512014 96 let t = self.resolve_vars_if_possible(t);
487cf647 97 t.error_reported()?;
ff7c6d11 98
f2b60f7d 99 if self.type_is_sized_modulo_regions(self.param_env, t, span) {
ff7c6d11 100 return Ok(Some(PointerKind::Thin));
abe05a73
XL
101 }
102
1b1a35ee 103 Ok(match *t.kind() {
b7449926 104 ty::Slice(_) | ty::Str => Some(PointerKind::Length),
f2b60f7d 105 ty::Dynamic(ref tty, _, ty::Dyn) => Some(PointerKind::VTable(tty.principal_def_id())),
dfeec247
XL
106 ty::Adt(def, substs) if def.is_struct() => match def.non_enum_variant().fields.last() {
107 None => Some(PointerKind::Thin),
108 Some(f) => {
109 let field_ty = self.field_ty(span, f, substs);
110 self.pointer_kind(field_ty, span)?
a7813a04 111 }
dfeec247 112 },
b7449926 113 ty::Tuple(fields) => match fields.last() {
ff7c6d11 114 None => Some(PointerKind::Thin),
5e7ed085 115 Some(&f) => self.pointer_kind(f, span)?,
ff7c6d11
XL
116 },
117
abe05a73 118 // Pointers to foreign types are thin, despite being unsized
b7449926 119 ty::Foreign(..) => Some(PointerKind::Thin),
a7813a04 120 // We should really try to normalize here.
f25598a0 121 ty::Alias(_, pi) => Some(PointerKind::OfAlias(pi)),
487cf647 122 ty::Param(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
f2b60f7d 141 | ty::Dynamic(_, _, ty::DynStar)
f035d41b 142 | ty::Error(_) => {
5e7ed085
FG
143 let reported = self
144 .tcx
dfeec247
XL
145 .sess
146 .delay_span_bug(span, &format!("`{:?}` should be sized but is not?", t));
5e7ed085 147 return Err(reported);
ff7c6d11
XL
148 }
149 })
62682a34
SL
150 }
151}
152
153#[derive(Copy, Clone)]
3dfed10e 154pub enum CastError {
f25598a0 155 ErrorGuaranteed(ErrorGuaranteed),
ff7c6d11 156
62682a34
SL
157 CastToBool,
158 CastToChar,
159 DifferingKinds,
9fa01778 160 /// Cast of thin to fat raw ptr (e.g., `*const () as *const [u8]`).
54a0048b 161 SizedUnsizedCast,
62682a34 162 IllegalCast,
476ff2be 163 NeedDeref,
62682a34 164 NeedViaPtr,
e9174d1e 165 NeedViaThinPtr,
62682a34 166 NeedViaInt,
62682a34 167 NonScalar,
abe05a73
XL
168 UnknownExprPtrKind,
169 UnknownCastPtrKind,
5e7ed085
FG
170 /// Cast of int to (possibly) fat raw pointer.
171 ///
172 /// Argument is the specific name of the metadata in plain words, such as "a vtable"
173 /// or "a length". If this argument is None, then the metadata is unknown, for example,
174 /// when we're typechecking a type parameter with a ?Sized bound.
175 IntToFatCast(Option<&'static str>),
f2b60f7d 176 ForeignNonExhaustiveAdt,
62682a34
SL
177}
178
5e7ed085 179impl From<ErrorGuaranteed> for CastError {
f25598a0
FG
180 fn from(err: ErrorGuaranteed) -> Self {
181 CastError::ErrorGuaranteed(err)
ff7c6d11
XL
182 }
183}
184
dc9dc135
XL
185fn make_invalid_casting_error<'a, 'tcx>(
186 sess: &'a Session,
187 span: Span,
188 expr_ty: Ty<'tcx>,
189 cast_ty: Ty<'tcx>,
190 fcx: &FnCtxt<'a, 'tcx>,
5e7ed085 191) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
dfeec247
XL
192 type_error_struct!(
193 sess,
194 span,
195 expr_ty,
196 E0606,
197 "casting `{}` as `{}` is invalid",
198 fcx.ty_to_string(expr_ty),
199 fcx.ty_to_string(cast_ty)
200 )
041b39d2
XL
201}
202
dc9dc135 203impl<'a, 'tcx> CastCheck<'tcx> {
2b03887a 204 pub fn new(
dc9dc135 205 fcx: &FnCtxt<'a, 'tcx>,
dfeec247 206 expr: &'tcx hir::Expr<'tcx>,
dc9dc135
XL
207 expr_ty: Ty<'tcx>,
208 cast_ty: Ty<'tcx>,
209 cast_span: Span,
210 span: Span,
2b03887a 211 constness: hir::Constness,
5e7ed085 212 ) -> Result<CastCheck<'tcx>, ErrorGuaranteed> {
04454e1e 213 let expr_span = expr.span.find_ancestor_inside(span).unwrap_or(expr.span);
2b03887a 214 let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span, constness };
a7813a04
XL
215
216 // For better error messages, check for some obviously unsized
217 // cases now. We do a more thorough check at the end, once
218 // inference is more completely known.
1b1a35ee 219 match cast_ty.kind() {
f2b60f7d 220 ty::Dynamic(_, _, ty::Dyn) | ty::Slice(..) => {
487cf647 221 Err(check.report_cast_to_unsized_type(fcx))
a7813a04 222 }
c30ab7b3 223 _ => Ok(check),
9346a6ac
AL
224 }
225 }
9346a6ac 226
dc9dc135 227 fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
62682a34 228 match e {
f25598a0 229 CastError::ErrorGuaranteed(_) => {
ff7c6d11
XL
230 // an error has already been reported
231 }
476ff2be 232 CastError::NeedDeref => {
dfeec247
XL
233 let mut err = make_invalid_casting_error(
234 fcx.tcx.sess,
235 self.span,
236 self.expr_ty,
237 self.cast_ty,
238 fcx,
239 );
f25598a0
FG
240
241 if matches!(self.expr.kind, ExprKind::AddrOf(..)) {
242 // get just the borrow part of the expression
243 let span = self.expr_span.with_hi(self.expr.peel_borrows().span.lo());
244 err.span_suggestion_verbose(
245 span,
246 "remove the unneeded borrow",
247 "",
248 Applicability::MachineApplicable,
0731742a
XL
249 );
250 } else {
f25598a0
FG
251 err.span_suggestion_verbose(
252 self.expr_span.shrink_to_lo(),
253 "dereference the expression",
254 "*",
255 Applicability::MachineApplicable,
256 );
476ff2be 257 }
f25598a0 258
476ff2be
SL
259 err.emit();
260 }
dfeec247
XL
261 CastError::NeedViaThinPtr | CastError::NeedViaPtr => {
262 let mut err = make_invalid_casting_error(
263 fcx.tcx.sess,
264 self.span,
265 self.expr_ty,
266 self.cast_ty,
267 fcx,
268 );
2c00a5a8 269 if self.cast_ty.is_integral() {
dfeec247
XL
270 err.help(&format!(
271 "cast through {} first",
272 match e {
273 CastError::NeedViaPtr => "a raw pointer",
274 CastError::NeedViaThinPtr => "a thin pointer",
275 _ => bug!(),
276 }
277 ));
476ff2be 278 }
f25598a0
FG
279
280 self.try_suggest_collection_to_bool(fcx, &mut err);
281
476ff2be
SL
282 err.emit();
283 }
284 CastError::NeedViaInt => {
dfeec247
XL
285 make_invalid_casting_error(
286 fcx.tcx.sess,
287 self.span,
288 self.expr_ty,
289 self.cast_ty,
290 fcx,
291 )
292 .help(&format!(
293 "cast through {} first",
294 match e {
295 CastError::NeedViaInt => "an integer",
296 _ => bug!(),
297 }
298 ))
299 .emit();
62682a34 300 }
041b39d2 301 CastError::IllegalCast => {
dfeec247
XL
302 make_invalid_casting_error(
303 fcx.tcx.sess,
304 self.span,
305 self.expr_ty,
306 self.cast_ty,
307 fcx,
308 )
309 .emit();
041b39d2
XL
310 }
311 CastError::DifferingKinds => {
dfeec247
XL
312 make_invalid_casting_error(
313 fcx.tcx.sess,
314 self.span,
315 self.expr_ty,
316 self.cast_ty,
317 fcx,
318 )
319 .note("vtable kinds may not match")
320 .emit();
041b39d2 321 }
62682a34 322 CastError::CastToBool => {
0731742a
XL
323 let mut err =
324 struct_span_err!(fcx.tcx.sess, self.span, E0054, "cannot cast as `bool`");
325
326 if self.expr_ty.is_numeric() {
04454e1e 327 match fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) {
0731742a 328 Ok(snippet) => {
9fa01778 329 err.span_suggestion(
0731742a
XL
330 self.span,
331 "compare with zero instead",
04454e1e 332 format!("{snippet} != 0"),
0731742a
XL
333 Applicability::MachineApplicable,
334 );
335 }
336 Err(_) => {
337 err.span_help(self.span, "compare with zero instead");
338 }
339 }
340 } else {
341 err.span_label(self.span, "unsupported cast");
342 }
343
344 err.emit();
62682a34
SL
345 }
346 CastError::CastToChar => {
5099ac24 347 let mut err = type_error_struct!(
dfeec247
XL
348 fcx.tcx.sess,
349 self.span,
350 self.expr_ty,
351 E0604,
352 "only `u8` can be cast as `char`, not `{}`",
353 self.expr_ty
5099ac24
FG
354 );
355 err.span_label(self.span, "invalid cast");
356 if self.expr_ty.is_numeric() {
923072b8
FG
357 if self.expr_ty == fcx.tcx.types.u32 {
358 match fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
359 Ok(snippet) => err.span_suggestion(
360 self.span,
361 "try `char::from_u32` instead",
362 format!("char::from_u32({snippet})"),
363 Applicability::MachineApplicable,
364 ),
365
366 Err(_) => err.span_help(self.span, "try `char::from_u32` instead"),
367 };
368 } else if self.expr_ty == fcx.tcx.types.i8 {
369 err.span_help(self.span, "try casting from `u8` instead");
370 } else {
371 err.span_help(self.span, "try `char::from_u32` instead (via a `u32`)");
372 };
5099ac24
FG
373 }
374 err.emit();
62682a34
SL
375 }
376 CastError::NonScalar => {
f035d41b 377 let mut err = type_error_struct!(
dfeec247
XL
378 fcx.tcx.sess,
379 self.span,
380 self.expr_ty,
381 E0605,
382 "non-primitive cast: `{}` as `{}`",
383 self.expr_ty,
384 fcx.ty_to_string(self.cast_ty)
f035d41b
XL
385 );
386 let mut sugg = None;
17df50a5 387 let mut sugg_mutref = false;
c295e0f8 388 if let ty::Ref(reg, cast_ty, mutbl) = *self.cast_ty.kind() {
04454e1e
FG
389 if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind()
390 && fcx
17df50a5
XL
391 .try_coerce(
392 self.expr,
393 fcx.tcx.mk_ref(
5099ac24 394 fcx.tcx.lifetimes.re_erased,
17df50a5
XL
395 TypeAndMut { ty: expr_ty, mutbl },
396 ),
397 self.cast_ty,
398 AllowTwoPhase::No,
c295e0f8 399 None,
17df50a5
XL
400 )
401 .is_ok()
04454e1e
FG
402 {
403 sugg = Some((format!("&{}*", mutbl.prefix_str()), cast_ty == expr_ty));
404 } else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind()
405 && expr_mutbl == Mutability::Not
406 && mutbl == Mutability::Mut
407 && fcx
408 .try_coerce(
409 self.expr,
410 fcx.tcx.mk_ref(
411 expr_reg,
412 TypeAndMut { ty: expr_ty, mutbl: Mutability::Mut },
413 ),
414 self.cast_ty,
415 AllowTwoPhase::No,
416 None,
417 )
418 .is_ok()
419 {
420 sugg_mutref = true;
17df50a5
XL
421 }
422
423 if !sugg_mutref
424 && sugg == None
425 && fcx
426 .try_coerce(
427 self.expr,
428 fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }),
429 self.cast_ty,
430 AllowTwoPhase::No,
c295e0f8 431 None,
17df50a5
XL
432 )
433 .is_ok()
f035d41b 434 {
c295e0f8 435 sugg = Some((format!("&{}", mutbl.prefix_str()), false));
f035d41b 436 }
04454e1e
FG
437 } else if let ty::RawPtr(TypeAndMut { mutbl, .. }) = *self.cast_ty.kind()
438 && fcx
cdc7bbd5
XL
439 .try_coerce(
440 self.expr,
441 fcx.tcx.mk_ref(
5099ac24 442 fcx.tcx.lifetimes.re_erased,
cdc7bbd5
XL
443 TypeAndMut { ty: self.expr_ty, mutbl },
444 ),
445 self.cast_ty,
446 AllowTwoPhase::No,
c295e0f8 447 None,
cdc7bbd5
XL
448 )
449 .is_ok()
04454e1e
FG
450 {
451 sugg = Some((format!("&{}", mutbl.prefix_str()), false));
f035d41b 452 }
17df50a5
XL
453 if sugg_mutref {
454 err.span_label(self.span, "invalid cast");
04454e1e 455 err.span_note(self.expr_span, "this reference is immutable");
17df50a5 456 err.span_note(self.cast_span, "trying to cast to a mutable reference type");
c295e0f8 457 } else if let Some((sugg, remove_cast)) = sugg {
f035d41b 458 err.span_label(self.span, "invalid cast");
c295e0f8
XL
459
460 let has_parens = fcx
461 .tcx
462 .sess
463 .source_map()
04454e1e 464 .span_to_snippet(self.expr_span)
c295e0f8
XL
465 .map_or(false, |snip| snip.starts_with('('));
466
467 // Very crude check to see whether the expression must be wrapped
468 // in parentheses for the suggestion to work (issue #89497).
469 // Can/should be extended in the future.
3c0e092e
XL
470 let needs_parens =
471 !has_parens && matches!(self.expr.kind, hir::ExprKind::Cast(..));
c295e0f8 472
04454e1e 473 let mut suggestion = vec![(self.expr_span.shrink_to_lo(), sugg)];
c295e0f8
XL
474 if needs_parens {
475 suggestion[0].1 += "(";
04454e1e 476 suggestion.push((self.expr_span.shrink_to_hi(), ")".to_string()));
c295e0f8
XL
477 }
478 if remove_cast {
479 suggestion.push((
04454e1e 480 self.expr_span.shrink_to_hi().to(self.cast_span),
c295e0f8
XL
481 String::new(),
482 ));
483 }
484
485 err.multipart_suggestion_verbose(
17df50a5 486 "consider borrowing the value",
c295e0f8 487 suggestion,
f035d41b
XL
488 Applicability::MachineApplicable,
489 );
490 } else if !matches!(
1b1a35ee 491 self.cast_ty.kind(),
f035d41b
XL
492 ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..)
493 ) {
494 let mut label = true;
495 // Check `impl From<self.expr_ty> for self.cast_ty {}` for accurate suggestion:
04454e1e
FG
496 if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr_span)
497 && let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::From)
498 {
499 let ty = fcx.resolve_vars_if_possible(self.cast_ty);
500 // Erase regions to avoid panic in `prove_value` when calling
501 // `type_implements_trait`.
502 let ty = fcx.tcx.erase_regions(ty);
503 let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
504 let expr_ty = fcx.tcx.erase_regions(expr_ty);
04454e1e
FG
505 if fcx
506 .infcx
487cf647 507 .type_implements_trait(from_trait, [ty, expr_ty], fcx.param_env)
04454e1e
FG
508 .must_apply_modulo_regions()
509 {
510 label = false;
511 err.span_suggestion(
512 self.span,
513 "consider using the `From` trait instead",
514 format!("{}::from({})", self.cast_ty, snippet),
515 Applicability::MaybeIncorrect,
516 );
f035d41b
XL
517 }
518 }
519 let msg = "an `as` expression can only be used to convert between primitive \
520 types or to coerce to a specific trait object";
521 if label {
522 err.span_label(self.span, msg);
523 } else {
524 err.note(msg);
525 }
526 } else {
527 err.span_label(self.span, "invalid cast");
528 }
f25598a0
FG
529
530 self.try_suggest_collection_to_bool(fcx, &mut err);
531
f035d41b 532 err.emit();
62682a34 533 }
54a0048b 534 CastError::SizedUnsizedCast => {
2b03887a
FG
535 use rustc_hir_analysis::structured_errors::{
536 SizedUnsizedCast, StructuredDiagnostic,
537 };
5869c6ff
XL
538
539 SizedUnsizedCast {
540 sess: &fcx.tcx.sess,
541 span: self.span,
542 expr_ty: self.expr_ty,
543 cast_ty: fcx.ty_to_string(self.cast_ty),
544 }
dfeec247
XL
545 .diagnostic()
546 .emit();
62682a34 547 }
5e7ed085
FG
548 CastError::IntToFatCast(known_metadata) => {
549 let mut err = struct_span_err!(
550 fcx.tcx.sess,
551 self.cast_span,
552 E0606,
553 "cannot cast `{}` to a pointer that {} wide",
554 fcx.ty_to_string(self.expr_ty),
555 if known_metadata.is_some() { "is" } else { "may be" }
556 );
557
558 err.span_label(
559 self.cast_span,
560 format!(
561 "creating a `{}` requires both an address and {}",
562 self.cast_ty,
563 known_metadata.unwrap_or("type-specific metadata"),
564 ),
565 );
566
567 if fcx.tcx.sess.is_nightly_build() {
568 err.span_label(
04454e1e 569 self.expr_span,
5e7ed085
FG
570 "consider casting this expression to `*const ()`, \
571 then using `core::ptr::from_raw_parts`",
572 );
573 }
574
575 err.emit();
576 }
dfeec247 577 CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => {
abe05a73
XL
578 let unknown_cast_to = match e {
579 CastError::UnknownCastPtrKind => true,
580 CastError::UnknownExprPtrKind => false,
581 _ => bug!(),
582 };
dfeec247
XL
583 let mut err = struct_span_err!(
584 fcx.tcx.sess,
f035d41b 585 if unknown_cast_to { self.cast_span } else { self.span },
dfeec247
XL
586 E0641,
587 "cannot cast {} a pointer of an unknown kind",
588 if unknown_cast_to { "to" } else { "from" }
589 );
abe05a73 590 if unknown_cast_to {
f035d41b
XL
591 err.span_label(self.cast_span, "needs more type information");
592 err.note(
593 "the type information given here is insufficient to check whether \
594 the pointer cast is valid",
595 );
596 } else {
597 err.span_label(
598 self.span,
599 "the type information given here is insufficient to check whether \
600 the pointer cast is valid",
0bf4aa26 601 );
abe05a73
XL
602 }
603 err.emit();
604 }
f2b60f7d
FG
605 CastError::ForeignNonExhaustiveAdt => {
606 make_invalid_casting_error(
607 fcx.tcx.sess,
608 self.span,
609 self.expr_ty,
610 self.cast_ty,
611 fcx,
612 )
613 .note("cannot cast an enum with a non-exhaustive variant when it's defined in another crate")
614 .emit();
615 }
62682a34
SL
616 }
617 }
618
5e7ed085 619 fn report_cast_to_unsized_type(&self, fcx: &FnCtxt<'a, 'tcx>) -> ErrorGuaranteed {
487cf647
FG
620 if let Err(err) = self.cast_ty.error_reported() {
621 return err;
622 }
623 if let Err(err) = self.expr_ty.error_reported() {
624 return err;
a7813a04
XL
625 }
626
627 let tstr = fcx.ty_to_string(self.cast_ty);
dfeec247
XL
628 let mut err = type_error_struct!(
629 fcx.tcx.sess,
630 self.span,
631 self.expr_ty,
632 E0620,
633 "cast to unsized type: `{}` as `{}`",
fc512014 634 fcx.resolve_vars_if_possible(self.expr_ty),
dfeec247
XL
635 tstr
636 );
1b1a35ee 637 match self.expr_ty.kind() {
b7449926 638 ty::Ref(_, _, mt) => {
60c5eb7d 639 let mtstr = mt.prefix_str();
a7813a04 640 if self.cast_ty.is_trait() {
b7449926 641 match fcx.tcx.sess.source_map().span_to_snippet(self.cast_span) {
a7813a04 642 Ok(s) => {
9fa01778 643 err.span_suggestion(
0bf4aa26
XL
644 self.cast_span,
645 "try casting to a reference instead",
646 format!("&{}{}", mtstr, s),
647 Applicability::MachineApplicable,
648 );
c30ab7b3
SL
649 }
650 Err(_) => {
dfeec247
XL
651 let msg = &format!("did you mean `&{}{}`?", mtstr, tstr);
652 err.span_help(self.cast_span, msg);
c30ab7b3 653 }
a7813a04
XL
654 }
655 } else {
04454e1e
FG
656 let msg =
657 &format!("consider using an implicit coercion to `&{mtstr}{tstr}` instead");
dfeec247 658 err.span_help(self.span, msg);
a7813a04
XL
659 }
660 }
b7449926
XL
661 ty::Adt(def, ..) if def.is_box() => {
662 match fcx.tcx.sess.source_map().span_to_snippet(self.cast_span) {
a7813a04 663 Ok(s) => {
9fa01778 664 err.span_suggestion(
0bf4aa26 665 self.cast_span,
f035d41b 666 "you can cast to a `Box` instead",
04454e1e 667 format!("Box<{s}>"),
0bf4aa26
XL
668 Applicability::MachineApplicable,
669 );
c30ab7b3 670 }
dfeec247 671 Err(_) => {
f035d41b
XL
672 err.span_help(
673 self.cast_span,
04454e1e 674 &format!("you might have meant `Box<{tstr}>`"),
f035d41b 675 );
dfeec247 676 }
a7813a04
XL
677 }
678 }
679 _ => {
04454e1e 680 err.span_help(self.expr_span, "consider using a box or reference as appropriate");
a7813a04
XL
681 }
682 }
5e7ed085 683 err.emit()
a7813a04
XL
684 }
685
dc9dc135 686 fn trivial_cast_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
62682a34
SL
687 let t_cast = self.cast_ty;
688 let t_expr = self.expr_ty;
dfeec247
XL
689 let type_asc_or =
690 if fcx.tcx.features().type_ascription { "type ascription or " } else { "" };
8faf50e0
XL
691 let (adjective, lint) = if t_cast.is_numeric() && t_expr.is_numeric() {
692 ("numeric ", lint::builtin::TRIVIAL_NUMERIC_CASTS)
693 } else {
694 ("", lint::builtin::TRIVIAL_CASTS)
695 };
2b03887a
FG
696 fcx.tcx.struct_span_lint_hir(
697 lint,
698 self.expr.hir_id,
699 self.span,
700 DelayDm(|| {
701 format!(
702 "trivial {}cast: `{}` as `{}`",
703 adjective,
704 fcx.ty_to_string(t_expr),
705 fcx.ty_to_string(t_cast)
706 )
707 }),
708 |lint| {
709 lint.help(format!(
710 "cast can be replaced by coercion; this might \
711 require {type_asc_or}a temporary variable"
712 ))
713 },
714 );
9346a6ac
AL
715 }
716
94222f64 717 #[instrument(skip(fcx), level = "debug")]
dc9dc135 718 pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) {
04454e1e 719 self.expr_ty = fcx.structurally_resolved_type(self.expr_span, self.expr_ty);
94222f64 720 self.cast_ty = fcx.structurally_resolved_type(self.cast_span, self.cast_ty);
62682a34 721
a2a8927a
XL
722 debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty);
723
f2b60f7d 724 if !fcx.type_is_sized_modulo_regions(fcx.param_env, self.cast_ty, self.span)
a2a8927a
XL
725 && !self.cast_ty.has_infer_types()
726 {
a7813a04
XL
727 self.report_cast_to_unsized_type(fcx);
728 } else if self.expr_ty.references_error() || self.cast_ty.references_error() {
62682a34 729 // No sense in giving duplicate error messages
c30ab7b3 730 } else {
e74abb32
XL
731 match self.try_coercion_cast(fcx) {
732 Ok(()) => {
733 self.trivial_cast_lint(fcx);
734 debug!(" -> CoercionCast");
3dfed10e 735 fcx.typeck_results.borrow_mut().set_coercion_cast(self.expr.hir_id.local_id);
e74abb32 736 }
e74abb32
XL
737 Err(_) => {
738 match self.do_check(fcx) {
739 Ok(k) => {
740 debug!(" -> {:?}", k);
741 }
742 Err(e) => self.report_cast_error(fcx, e),
743 };
c30ab7b3 744 }
c30ab7b3
SL
745 };
746 }
62682a34 747 }
9fa01778 748 /// Checks a cast, and report an error if one exists. In some cases, this
62682a34
SL
749 /// can return Ok and create type errors in the fcx rather than returning
750 /// directly. coercion-cast is handled in check instead of here.
3dfed10e 751 pub fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
ba9703b0
XL
752 use rustc_middle::ty::cast::CastTy::*;
753 use rustc_middle::ty::cast::IntTy::*;
62682a34 754
dfeec247
XL
755 let (t_from, t_cast) = match (CastTy::from_ty(self.expr_ty), CastTy::from_ty(self.cast_ty))
756 {
62682a34 757 (Some(t_from), Some(t_cast)) => (t_from, t_cast),
54a0048b
SL
758 // Function item types may need to be reified before casts.
759 (None, Some(t_cast)) => {
1b1a35ee 760 match *self.expr_ty.kind() {
dfeec247
XL
761 ty::FnDef(..) => {
762 // Attempt a coercion to a fn pointer type.
487cf647 763 let f = fcx.normalize(self.expr_span, self.expr_ty.fn_sig(fcx.tcx));
dfeec247
XL
764 let res = fcx.try_coerce(
765 self.expr,
766 self.expr_ty,
767 fcx.tcx.mk_fn_ptr(f),
768 AllowTwoPhase::No,
c295e0f8 769 None,
dfeec247
XL
770 );
771 if let Err(TypeError::IntrinsicCast) = res {
772 return Err(CastError::IllegalCast);
773 }
774 if res.is_err() {
775 return Err(CastError::NonScalar);
776 }
777 (FnPtr, t_cast)
e1599b0c 778 }
dfeec247
XL
779 // Special case some errors for references, and check for
780 // array-ptr-casts. `Ref` is not a CastTy because the cast
781 // is split into a coercion to a pointer type, followed by
782 // a cast.
783 ty::Ref(_, inner_ty, mutbl) => {
784 return match t_cast {
1b1a35ee 785 Int(_) | Float => match *inner_ty.kind() {
dfeec247
XL
786 ty::Int(_)
787 | ty::Uint(_)
788 | ty::Float(_)
ba9703b0
XL
789 | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(_)) => {
790 Err(CastError::NeedDeref)
791 }
dfeec247
XL
792 _ => Err(CastError::NeedViaPtr),
793 },
794 // array-ptr-cast
795 Ptr(mt) => {
796 self.check_ref_cast(fcx, TypeAndMut { mutbl, ty: inner_ty }, mt)
797 }
798 _ => Err(CastError::NonScalar),
799 };
54a0048b 800 }
dfeec247 801 _ => return Err(CastError::NonScalar),
54a0048b
SL
802 }
803 }
c30ab7b3 804 _ => return Err(CastError::NonScalar),
62682a34
SL
805 };
806
f2b60f7d
FG
807 if let ty::Adt(adt_def, _) = *self.expr_ty.kind() {
808 if adt_def.did().krate != LOCAL_CRATE {
809 if adt_def.variants().iter().any(VariantDef::is_field_list_non_exhaustive) {
810 return Err(CastError::ForeignNonExhaustiveAdt);
811 }
812 }
813 }
814
62682a34
SL
815 match (t_from, t_cast) {
816 // These types have invariants! can't cast into them.
ba9703b0 817 (_, Int(CEnum) | FnPtr) => Err(CastError::NonScalar),
62682a34
SL
818
819 // * -> Bool
820 (_, Int(Bool)) => Err(CastError::CastToBool),
821
822 // * -> Char
5869c6ff 823 (Int(U(ty::UintTy::U8)), Int(Char)) => Ok(CastKind::U8CharCast), // u8-char-cast
62682a34
SL
824 (_, Int(Char)) => Err(CastError::CastToChar),
825
826 // prim -> float,ptr
ba9703b0 827 (Int(Bool) | Int(CEnum) | Int(Char), Float) => Err(CastError::NeedViaInt),
476ff2be 828
ba9703b0
XL
829 (Int(Bool) | Int(CEnum) | Int(Char) | Float, Ptr(_)) | (Ptr(_) | FnPtr, Float) => {
830 Err(CastError::IllegalCast)
831 }
62682a34
SL
832
833 // ptr -> *
834 (Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
dfeec247 835
04454e1e
FG
836 // ptr-addr-cast
837 (Ptr(m_expr), Int(t_c)) => {
838 self.lossy_provenance_ptr2int_lint(fcx, t_c);
839 self.check_ptr_addr_cast(fcx, m_expr)
840 }
841 (FnPtr, Int(_)) => {
842 // FIXME(#95489): there should eventually be a lint for these casts
843 Ok(CastKind::FnPtrAddrCast)
844 }
845 // addr-ptr-cast
846 (Int(_), Ptr(mt)) => {
847 self.fuzzy_provenance_int2ptr_lint(fcx);
848 self.check_addr_ptr_cast(fcx, mt)
849 }
850 // fn-ptr-cast
62682a34 851 (FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
62682a34
SL
852
853 // prim -> prim
f035d41b
XL
854 (Int(CEnum), Int(_)) => {
855 self.cenum_impl_drop_lint(fcx);
856 Ok(CastKind::EnumCast)
857 }
ba9703b0 858 (Int(Char) | Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast),
62682a34 859
ba9703b0 860 (Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast),
f2b60f7d 861
f25598a0 862 (_, DynStar) => {
2b03887a
FG
863 if fcx.tcx.features().dyn_star {
864 bug!("should be handled by `try_coerce`")
865 } else {
866 Err(CastError::IllegalCast)
867 }
868 }
f25598a0
FG
869
870 (DynStar, _) => Err(CastError::IllegalCast),
9346a6ac
AL
871 }
872 }
873
dc9dc135
XL
874 fn check_ptr_ptr_cast(
875 &self,
876 fcx: &FnCtxt<'a, 'tcx>,
877 m_expr: ty::TypeAndMut<'tcx>,
878 m_cast: ty::TypeAndMut<'tcx>,
879 ) -> Result<CastKind, CastError> {
c30ab7b3 880 debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", m_expr, m_cast);
62682a34
SL
881 // ptr-ptr cast. vtables must match.
882
ff7c6d11
XL
883 let expr_kind = fcx.pointer_kind(m_expr.ty, self.span)?;
884 let cast_kind = fcx.pointer_kind(m_cast.ty, self.span)?;
abe05a73 885
5e7ed085 886 let Some(cast_kind) = cast_kind else {
abe05a73 887 // We can't cast if target pointer kind is unknown
5e7ed085 888 return Err(CastError::UnknownCastPtrKind);
abe05a73
XL
889 };
890
891 // Cast to thin pointer is OK
892 if cast_kind == PointerKind::Thin {
62682a34 893 return Ok(CastKind::PtrPtrCast);
9346a6ac 894 }
62682a34 895
5e7ed085 896 let Some(expr_kind) = expr_kind else {
abe05a73 897 // We can't cast to fat pointer if source pointer kind is unknown
5e7ed085 898 return Err(CastError::UnknownExprPtrKind);
abe05a73
XL
899 };
900
901 // thin -> fat? report invalid cast (don't complain about vtable kinds)
902 if expr_kind == PointerKind::Thin {
54a0048b 903 return Err(CastError::SizedUnsizedCast);
9346a6ac 904 }
9346a6ac 905
62682a34 906 // vtable kinds must match
487cf647 907 if fcx.tcx.erase_regions(cast_kind) == fcx.tcx.erase_regions(expr_kind) {
abe05a73
XL
908 Ok(CastKind::PtrPtrCast)
909 } else {
910 Err(CastError::DifferingKinds)
9346a6ac 911 }
62682a34 912 }
9346a6ac 913
dc9dc135
XL
914 fn check_fptr_ptr_cast(
915 &self,
916 fcx: &FnCtxt<'a, 'tcx>,
917 m_cast: ty::TypeAndMut<'tcx>,
918 ) -> Result<CastKind, CastError> {
abe05a73 919 // fptr-ptr cast. must be to thin ptr
62682a34 920
ff7c6d11 921 match fcx.pointer_kind(m_cast.ty, self.span)? {
abe05a73
XL
922 None => Err(CastError::UnknownCastPtrKind),
923 Some(PointerKind::Thin) => Ok(CastKind::FnPtrPtrCast),
924 _ => Err(CastError::IllegalCast),
62682a34
SL
925 }
926 }
927
dc9dc135
XL
928 fn check_ptr_addr_cast(
929 &self,
930 fcx: &FnCtxt<'a, 'tcx>,
931 m_expr: ty::TypeAndMut<'tcx>,
932 ) -> Result<CastKind, CastError> {
abe05a73 933 // ptr-addr cast. must be from thin ptr
62682a34 934
ff7c6d11 935 match fcx.pointer_kind(m_expr.ty, self.span)? {
abe05a73
XL
936 None => Err(CastError::UnknownExprPtrKind),
937 Some(PointerKind::Thin) => Ok(CastKind::PtrAddrCast),
938 _ => Err(CastError::NeedViaThinPtr),
62682a34
SL
939 }
940 }
941
dc9dc135
XL
942 fn check_ref_cast(
943 &self,
944 fcx: &FnCtxt<'a, 'tcx>,
945 m_expr: ty::TypeAndMut<'tcx>,
946 m_cast: ty::TypeAndMut<'tcx>,
947 ) -> Result<CastKind, CastError> {
6a06907d 948 // array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const
487cf647 949 if m_expr.mutbl >= m_cast.mutbl {
1b1a35ee 950 if let ty::Array(ety, _) = m_expr.ty.kind() {
62682a34
SL
951 // Due to the limitations of LLVM global constants,
952 // region pointers end up pointing at copies of
953 // vector elements instead of the original values.
954 // To allow raw pointers to work correctly, we
955 // need to special-case obtaining a raw pointer
956 // from a region pointer to a vector.
957
60c5eb7d
XL
958 // Coerce to a raw pointer so that we generate AddressOf in MIR.
959 let array_ptr_type = fcx.tcx.mk_ptr(m_expr);
c295e0f8 960 fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None)
f035d41b
XL
961 .unwrap_or_else(|_| {
962 bug!(
60c5eb7d
XL
963 "could not cast from reference to array to pointer to array ({:?} to {:?})",
964 self.expr_ty,
965 array_ptr_type,
f035d41b
XL
966 )
967 });
60c5eb7d 968
62682a34 969 // this will report a type mismatch if needed
5099ac24 970 fcx.demand_eqtype(self.span, *ety, m_cast.ty);
62682a34 971 return Ok(CastKind::ArrayPtrCast);
9346a6ac
AL
972 }
973 }
62682a34
SL
974
975 Err(CastError::IllegalCast)
976 }
977
dc9dc135
XL
978 fn check_addr_ptr_cast(
979 &self,
980 fcx: &FnCtxt<'a, 'tcx>,
981 m_cast: TypeAndMut<'tcx>,
982 ) -> Result<CastKind, CastError> {
62682a34 983 // ptr-addr cast. pointer must be thin.
ff7c6d11 984 match fcx.pointer_kind(m_cast.ty, self.span)? {
abe05a73
XL
985 None => Err(CastError::UnknownCastPtrKind),
986 Some(PointerKind::Thin) => Ok(CastKind::AddrPtrCast),
064997fb 987 Some(PointerKind::VTable(_)) => Err(CastError::IntToFatCast(Some("a vtable"))),
5e7ed085 988 Some(PointerKind::Length) => Err(CastError::IntToFatCast(Some("a length"))),
f25598a0
FG
989 Some(PointerKind::OfAlias(_) | PointerKind::OfParam(_)) => {
990 Err(CastError::IntToFatCast(None))
991 }
d9579d0f 992 }
9346a6ac 993 }
62682a34 994
923072b8 995 fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<(), ty::error::TypeError<'tcx>> {
c295e0f8 996 match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No, None) {
e74abb32
XL
997 Ok(_) => Ok(()),
998 Err(err) => Err(err),
999 }
62682a34 1000 }
f035d41b
XL
1001
1002 fn cenum_impl_drop_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
04454e1e
FG
1003 if let ty::Adt(d, _) = self.expr_ty.kind()
1004 && d.has_dtor(fcx.tcx)
1005 {
1006 fcx.tcx.struct_span_lint_hir(
1007 lint::builtin::CENUM_IMPL_DROP_CAST,
1008 self.expr.hir_id,
1009 self.span,
2b03887a
FG
1010 DelayDm(|| format!(
1011 "cannot cast enum `{}` into integer `{}` because it implements `Drop`",
1012 self.expr_ty, self.cast_ty
1013 )),
1014 |lint| {
1015 lint
04454e1e
FG
1016 },
1017 );
f035d41b
XL
1018 }
1019 }
04454e1e
FG
1020
1021 fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::IntTy) {
1022 fcx.tcx.struct_span_lint_hir(
1023 lint::builtin::LOSSY_PROVENANCE_CASTS,
1024 self.expr.hir_id,
1025 self.span,
2b03887a 1026 DelayDm(|| format!(
04454e1e
FG
1027 "under strict provenance it is considered bad style to cast pointer `{}` to integer `{}`",
1028 self.expr_ty, self.cast_ty
2b03887a
FG
1029 )),
1030 |lint| {
04454e1e
FG
1031 let msg = "use `.addr()` to obtain the address of a pointer";
1032
1033 let expr_prec = self.expr.precedence().order();
1034 let needs_parens = expr_prec < rustc_ast::util::parser::PREC_POSTFIX;
1035
1036 let scalar_cast = match t_c {
1037 ty::cast::IntTy::U(ty::UintTy::Usize) => String::new(),
1038 _ => format!(" as {}", self.cast_ty),
1039 };
1040
1041 let cast_span = self.expr_span.shrink_to_hi().to(self.cast_span);
1042
1043 if needs_parens {
1044 let suggestions = vec![
1045 (self.expr_span.shrink_to_lo(), String::from("(")),
1046 (cast_span, format!(").addr(){scalar_cast}")),
1047 ];
1048
2b03887a 1049 lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
04454e1e 1050 } else {
2b03887a 1051 lint.span_suggestion(
04454e1e
FG
1052 cast_span,
1053 msg,
1054 format!(".addr(){scalar_cast}"),
1055 Applicability::MaybeIncorrect,
1056 );
1057 }
1058
2b03887a 1059 lint.help(
04454e1e
FG
1060 "if you can't comply with strict provenance and need to expose the pointer \
1061 provenance you can use `.expose_addr()` instead"
1062 );
1063
2b03887a 1064 lint
04454e1e
FG
1065 },
1066 );
1067 }
1068
1069 fn fuzzy_provenance_int2ptr_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
1070 fcx.tcx.struct_span_lint_hir(
1071 lint::builtin::FUZZY_PROVENANCE_CASTS,
1072 self.expr.hir_id,
1073 self.span,
2b03887a
FG
1074 DelayDm(|| format!(
1075 "strict provenance disallows casting integer `{}` to pointer `{}`",
1076 self.expr_ty, self.cast_ty
1077 )),
1078 |lint| {
04454e1e
FG
1079 let msg = "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address";
1080 let suggestions = vec![
1081 (self.expr_span.shrink_to_lo(), String::from("(...).with_addr(")),
1082 (self.expr_span.shrink_to_hi().to(self.cast_span), String::from(")")),
1083 ];
1084
2b03887a
FG
1085 lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
1086 lint.help(
04454e1e
FG
1087 "if you can't comply with strict provenance and don't have a pointer with \
1088 the correct provenance you can use `std::ptr::from_exposed_addr()` instead"
1089 );
1090
2b03887a 1091 lint
04454e1e
FG
1092 },
1093 );
1094 }
f25598a0
FG
1095
1096 /// Attempt to suggest using `.is_empty` when trying to cast from a
1097 /// collection type to a boolean.
1098 fn try_suggest_collection_to_bool(&self, fcx: &FnCtxt<'a, 'tcx>, err: &mut Diagnostic) {
1099 if self.cast_ty.is_bool() {
1100 let derefed = fcx
1101 .autoderef(self.expr_span, self.expr_ty)
1102 .silence_errors()
1103 .find(|t| matches!(t.0.kind(), ty::Str | ty::Slice(..)));
1104
1105 if let Some((deref_ty, _)) = derefed {
1106 // Give a note about what the expr derefs to.
1107 if deref_ty != self.expr_ty.peel_refs() {
1108 err.span_note(
1109 self.expr_span,
1110 format!(
1111 "this expression `Deref`s to `{}` which implements `is_empty`",
1112 fcx.ty_to_string(deref_ty)
1113 ),
1114 );
1115 }
1116
1117 // Create a multipart suggestion: add `!` and `.is_empty()` in
1118 // place of the cast.
1119 let suggestion = vec![
1120 (self.expr_span.shrink_to_lo(), "!".to_string()),
1121 (self.span.with_lo(self.expr_span.hi()), ".is_empty()".to_string()),
1122 ];
1123
1124 err.multipart_suggestion_verbose(format!(
1125 "consider using the `is_empty` method on `{}` to determine if it contains anything",
1126 fcx.ty_to_string(self.expr_ty),
1127 ), suggestion, Applicability::MaybeIncorrect);
1128 }
1129 }
1130 }
9346a6ac 1131}