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