1 //! Code for type-checking cast expressions.
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
6 //! pointer_kind(`T`) = pointer_kind(`U_0`); *ptr-ptr-cast*
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*
18 //! where `&.T` and `*T` are references of either mutability,
19 //! and where pointer_kind(`T`) is the kind of the unsize info
20 //! in `T` - the vtable for a trait definition (e.g., `fmt::Display` or
21 //! `Iterator`, not `Iterator<Item=u8>`) or a length (or `()` if `T: Sized`).
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.
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`).
33 use crate::hir
::def_id
::DefId
;
34 use crate::type_error_struct
;
35 use rustc_errors
::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}
;
37 use rustc_hir
::lang_items
::LangItem
;
38 use rustc_middle
::mir
::Mutability
;
39 use rustc_middle
::ty
::adjustment
::AllowTwoPhase
;
40 use rustc_middle
::ty
::cast
::{CastKind, CastTy}
;
41 use rustc_middle
::ty
::error
::TypeError
;
42 use rustc_middle
::ty
::subst
::SubstsRef
;
43 use rustc_middle
::ty
::{self, Ty, TypeAndMut, TypeFoldable}
;
44 use rustc_session
::lint
;
45 use rustc_session
::Session
;
46 use rustc_span
::symbol
::sym
;
48 use rustc_trait_selection
::infer
::InferCtxtExt
;
49 use rustc_trait_selection
::traits
;
50 use rustc_trait_selection
::traits
::error_reporting
::report_object_safety_error
;
52 /// Reifies a cast check to be checked once we have full type information for
53 /// a function context.
54 pub struct CastCheck
<'tcx
> {
55 expr
: &'tcx hir
::Expr
<'tcx
>,
62 /// The kind of pointer and associated metadata (thin, length or vtable) - we
63 /// only allow casts between fat pointers if their metadata have the same
65 #[derive(Copy, Clone, PartialEq, Eq)]
66 enum PointerKind
<'tcx
> {
67 /// No metadata attached, ie pointer to sized type or foreign type
70 Vtable(Option
<DefId
>),
73 /// The unsize info of this projection
74 OfProjection(&'tcx ty
::ProjectionTy
<'tcx
>),
75 /// The unsize info of this opaque ty
76 OfOpaque(DefId
, SubstsRef
<'tcx
>),
77 /// The unsize info of this parameter
78 OfParam(&'tcx ty
::ParamTy
),
81 impl<'a
, 'tcx
> FnCtxt
<'a
, 'tcx
> {
82 /// Returns the kind of unsize information of t, or None
88 ) -> Result
<Option
<PointerKind
<'tcx
>>, ErrorReported
> {
89 debug
!("pointer_kind({:?}, {:?})", t
, span
);
91 let t
= self.resolve_vars_if_possible(t
);
93 if t
.references_error() {
94 return Err(ErrorReported
);
97 if self.type_is_known_to_be_sized_modulo_regions(t
, span
) {
98 return Ok(Some(PointerKind
::Thin
));
102 ty
::Slice(_
) | ty
::Str
=> Some(PointerKind
::Length
),
103 ty
::Dynamic(ref tty
, ..) => Some(PointerKind
::Vtable(tty
.principal_def_id())),
104 ty
::Adt(def
, substs
) if def
.is_struct() => match def
.non_enum_variant().fields
.last() {
105 None
=> Some(PointerKind
::Thin
),
107 let field_ty
= self.field_ty(span
, f
, substs
);
108 self.pointer_kind(field_ty
, span
)?
111 ty
::Tuple(fields
) => match fields
.last() {
112 None
=> Some(PointerKind
::Thin
),
113 Some(f
) => self.pointer_kind(f
.expect_ty(), span
)?
,
116 // Pointers to foreign types are thin, despite being unsized
117 ty
::Foreign(..) => Some(PointerKind
::Thin
),
118 // We should really try to normalize here.
119 ty
::Projection(ref pi
) => Some(PointerKind
::OfProjection(pi
)),
120 ty
::Opaque(def_id
, substs
) => Some(PointerKind
::OfOpaque(def_id
, substs
)),
121 ty
::Param(ref p
) => Some(PointerKind
::OfParam(p
)),
122 // Insufficient type information.
123 ty
::Placeholder(..) | ty
::Bound(..) | ty
::Infer(_
) => None
,
131 | ty
::GeneratorWitness(..)
143 .delay_span_bug(span
, &format
!("`{:?}` should be sized but is not?", t
));
144 return Err(ErrorReported
);
150 #[derive(Copy, Clone)]
157 /// Cast of thin to fat raw ptr (e.g., `*const () as *const [u8]`).
169 impl From
<ErrorReported
> for CastError
{
170 fn from(ErrorReported
: ErrorReported
) -> Self {
171 CastError
::ErrorReported
175 fn make_invalid_casting_error
<'a
, 'tcx
>(
180 fcx
: &FnCtxt
<'a
, 'tcx
>,
181 ) -> DiagnosticBuilder
<'a
> {
187 "casting `{}` as `{}` is invalid",
188 fcx
.ty_to_string(expr_ty
),
189 fcx
.ty_to_string(cast_ty
)
193 impl<'a
, 'tcx
> CastCheck
<'tcx
> {
195 fcx
: &FnCtxt
<'a
, 'tcx
>,
196 expr
: &'tcx hir
::Expr
<'tcx
>,
201 ) -> Result
<CastCheck
<'tcx
>, ErrorReported
> {
202 let check
= CastCheck { expr, expr_ty, cast_ty, cast_span, span }
;
204 // For better error messages, check for some obviously unsized
205 // cases now. We do a more thorough check at the end, once
206 // inference is more completely known.
207 match cast_ty
.kind() {
208 ty
::Dynamic(..) | ty
::Slice(..) => {
209 check
.report_cast_to_unsized_type(fcx
);
216 fn report_cast_error(&self, fcx
: &FnCtxt
<'a
, 'tcx
>, e
: CastError
) {
218 CastError
::ErrorReported
=> {
219 // an error has already been reported
221 CastError
::NeedDeref
=> {
222 let error_span
= self.span
;
223 let mut err
= make_invalid_casting_error(
230 let cast_ty
= fcx
.ty_to_string(self.cast_ty
);
233 format
!("cannot cast `{}` as `{}`", fcx
.ty_to_string(self.expr_ty
), cast_ty
),
235 if let Ok(snippet
) = fcx
.sess().source_map().span_to_snippet(self.expr
.span
) {
238 "dereference the expression",
239 format
!("*{}", snippet
),
240 Applicability
::MaybeIncorrect
,
243 err
.span_help(self.expr
.span
, "dereference the expression with `*`");
247 CastError
::NeedViaThinPtr
| CastError
::NeedViaPtr
=> {
248 let mut err
= make_invalid_casting_error(
255 if self.cast_ty
.is_integral() {
257 "cast through {} first",
259 CastError
::NeedViaPtr
=> "a raw pointer",
260 CastError
::NeedViaThinPtr
=> "a thin pointer",
267 CastError
::NeedViaInt
=> {
268 make_invalid_casting_error(
276 "cast through {} first",
278 CastError
::NeedViaInt
=> "an integer",
284 CastError
::IllegalCast
=> {
285 make_invalid_casting_error(
294 CastError
::DifferingKinds
=> {
295 make_invalid_casting_error(
302 .note("vtable kinds may not match")
305 CastError
::CastToBool
=> {
307 struct_span_err
!(fcx
.tcx
.sess
, self.span
, E0054
, "cannot cast as `bool`");
309 if self.expr_ty
.is_numeric() {
310 match fcx
.tcx
.sess
.source_map().span_to_snippet(self.expr
.span
) {
314 "compare with zero instead",
315 format
!("{} != 0", snippet
),
316 Applicability
::MachineApplicable
,
320 err
.span_help(self.span
, "compare with zero instead");
324 err
.span_label(self.span
, "unsupported cast");
329 CastError
::CastToChar
=> {
335 "only `u8` can be cast as `char`, not `{}`",
338 .span_label(self.span
, "invalid cast")
341 CastError
::NonScalar
=> {
342 let mut err
= type_error_struct
!(
347 "non-primitive cast: `{}` as `{}`",
349 fcx
.ty_to_string(self.cast_ty
)
352 let mut sugg_mutref
= false;
353 if let ty
::Ref(reg
, _
, mutbl
) = *self.cast_ty
.kind() {
354 if let ty
::RawPtr(TypeAndMut { ty: expr_ty, .. }
) = *self.expr_ty
.kind() {
359 &ty
::RegionKind
::ReErased
,
360 TypeAndMut { ty: expr_ty, mutbl }
,
367 sugg
= Some(format
!("&{}*", mutbl
.prefix_str()));
369 } else if let ty
::Ref(expr_reg
, expr_ty
, expr_mutbl
) = *self.expr_ty
.kind() {
370 if expr_mutbl
== Mutability
::Not
371 && mutbl
== Mutability
::Mut
377 TypeAndMut { ty: expr_ty, mutbl: Mutability::Mut }
,
393 fcx
.tcx
.mk_ref(reg
, TypeAndMut { ty: self.expr_ty, mutbl }
),
399 sugg
= Some(format
!("&{}", mutbl
.prefix_str()));
401 } else if let ty
::RawPtr(TypeAndMut { mutbl, .. }
) = *self.cast_ty
.kind() {
406 &ty
::RegionKind
::ReErased
,
407 TypeAndMut { ty: self.expr_ty, mutbl }
,
414 sugg
= Some(format
!("&{}", mutbl
.prefix_str()));
418 err
.span_label(self.span
, "invalid cast");
419 err
.span_note(self.expr
.span
, "this reference is immutable");
420 err
.span_note(self.cast_span
, "trying to cast to a mutable reference type");
421 } else if let Some(sugg
) = sugg
{
422 err
.span_label(self.span
, "invalid cast");
423 err
.span_suggestion_verbose(
424 self.expr
.span
.shrink_to_lo(),
425 "consider borrowing the value",
427 Applicability
::MachineApplicable
,
431 ty
::FnDef(..) | ty
::FnPtr(..) | ty
::Closure(..)
433 let mut label
= true;
434 // Check `impl From<self.expr_ty> for self.cast_ty {}` for accurate suggestion:
435 if let Ok(snippet
) = fcx
.tcx
.sess
.source_map().span_to_snippet(self.expr
.span
) {
436 if let Some(from_trait
) = fcx
.tcx
.get_diagnostic_item(sym
::from_trait
) {
437 let ty
= fcx
.resolve_vars_if_possible(self.cast_ty
);
438 // Erase regions to avoid panic in `prove_value` when calling
439 // `type_implements_trait`.
440 let ty
= fcx
.tcx
.erase_regions(ty
);
441 let expr_ty
= fcx
.resolve_vars_if_possible(self.expr_ty
);
442 let expr_ty
= fcx
.tcx
.erase_regions(expr_ty
);
443 let ty_params
= fcx
.tcx
.mk_substs_trait(expr_ty
, &[]);
446 .type_implements_trait(from_trait
, ty
, ty_params
, fcx
.param_env
)
447 .must_apply_modulo_regions()
452 "consider using the `From` trait instead",
453 format
!("{}::from({})", self.cast_ty
, snippet
),
454 Applicability
::MaybeIncorrect
,
459 let msg
= "an `as` expression can only be used to convert between primitive \
460 types or to coerce to a specific trait object";
462 err
.span_label(self.span
, msg
);
467 err
.span_label(self.span
, "invalid cast");
471 CastError
::SizedUnsizedCast
=> {
472 use crate::structured_errors
::{SizedUnsizedCast, StructuredDiagnostic}
;
477 expr_ty
: self.expr_ty
,
478 cast_ty
: fcx
.ty_to_string(self.cast_ty
),
483 CastError
::UnknownCastPtrKind
| CastError
::UnknownExprPtrKind
=> {
484 let unknown_cast_to
= match e
{
485 CastError
::UnknownCastPtrKind
=> true,
486 CastError
::UnknownExprPtrKind
=> false,
489 let mut err
= struct_span_err
!(
491 if unknown_cast_to { self.cast_span }
else { self.span }
,
493 "cannot cast {} a pointer of an unknown kind",
494 if unknown_cast_to { "to" }
else { "from" }
497 err
.span_label(self.cast_span
, "needs more type information");
499 "the type information given here is insufficient to check whether \
500 the pointer cast is valid",
505 "the type information given here is insufficient to check whether \
506 the pointer cast is valid",
514 fn report_cast_to_unsized_type(&self, fcx
: &FnCtxt
<'a
, 'tcx
>) {
515 if self.cast_ty
.references_error() || self.expr_ty
.references_error() {
519 let tstr
= fcx
.ty_to_string(self.cast_ty
);
520 let mut err
= type_error_struct
!(
525 "cast to unsized type: `{}` as `{}`",
526 fcx
.resolve_vars_if_possible(self.expr_ty
),
529 match self.expr_ty
.kind() {
530 ty
::Ref(_
, _
, mt
) => {
531 let mtstr
= mt
.prefix_str();
532 if self.cast_ty
.is_trait() {
533 match fcx
.tcx
.sess
.source_map().span_to_snippet(self.cast_span
) {
537 "try casting to a reference instead",
538 format
!("&{}{}", mtstr
, s
),
539 Applicability
::MachineApplicable
,
543 let msg
= &format
!("did you mean `&{}{}`?", mtstr
, tstr
);
544 err
.span_help(self.cast_span
, msg
);
549 "consider using an implicit coercion to `&{}{}` instead",
552 err
.span_help(self.span
, msg
);
555 ty
::Adt(def
, ..) if def
.is_box() => {
556 match fcx
.tcx
.sess
.source_map().span_to_snippet(self.cast_span
) {
560 "you can cast to a `Box` instead",
561 format
!("Box<{}>", s
),
562 Applicability
::MachineApplicable
,
568 &format
!("you might have meant `Box<{}>`", tstr
),
574 err
.span_help(self.expr
.span
, "consider using a box or reference as appropriate");
580 fn trivial_cast_lint(&self, fcx
: &FnCtxt
<'a
, 'tcx
>) {
581 let t_cast
= self.cast_ty
;
582 let t_expr
= self.expr_ty
;
584 if fcx
.tcx
.features().type_ascription { "type ascription or " }
else { "" }
;
585 let (adjective
, lint
) = if t_cast
.is_numeric() && t_expr
.is_numeric() {
586 ("numeric ", lint
::builtin
::TRIVIAL_NUMERIC_CASTS
)
588 ("", lint
::builtin
::TRIVIAL_CASTS
)
590 fcx
.tcx
.struct_span_lint_hir(lint
, self.expr
.hir_id
, self.span
, |err
| {
592 "trivial {}cast: `{}` as `{}`",
594 fcx
.ty_to_string(t_expr
),
595 fcx
.ty_to_string(t_cast
)
598 "cast can be replaced by coercion; this might \
599 require {}a temporary variable",
606 pub fn check(mut self, fcx
: &FnCtxt
<'a
, 'tcx
>) {
607 self.expr_ty
= fcx
.structurally_resolved_type(self.span
, self.expr_ty
);
608 self.cast_ty
= fcx
.structurally_resolved_type(self.span
, self.cast_ty
);
610 debug
!("check_cast({}, {:?} as {:?})", self.expr
.hir_id
, self.expr_ty
, self.cast_ty
);
612 if !fcx
.type_is_known_to_be_sized_modulo_regions(self.cast_ty
, self.span
) {
613 self.report_cast_to_unsized_type(fcx
);
614 } else if self.expr_ty
.references_error() || self.cast_ty
.references_error() {
615 // No sense in giving duplicate error messages
617 match self.try_coercion_cast(fcx
) {
619 self.trivial_cast_lint(fcx
);
620 debug
!(" -> CoercionCast");
621 fcx
.typeck_results
.borrow_mut().set_coercion_cast(self.expr
.hir_id
.local_id
);
623 Err(ty
::error
::TypeError
::ObjectUnsafeCoercion(did
)) => {
624 self.report_object_unsafe_cast(&fcx
, did
);
627 match self.do_check(fcx
) {
629 debug
!(" -> {:?}", k
);
631 Err(e
) => self.report_cast_error(fcx
, e
),
638 fn report_object_unsafe_cast(&self, fcx
: &FnCtxt
<'a
, 'tcx
>, did
: DefId
) {
639 let violations
= fcx
.tcx
.object_safety_violations(did
);
640 let mut err
= report_object_safety_error(fcx
.tcx
, self.cast_span
, did
, violations
);
641 err
.note(&format
!("required by cast to type '{}'", fcx
.ty_to_string(self.cast_ty
)));
645 /// Checks a cast, and report an error if one exists. In some cases, this
646 /// can return Ok and create type errors in the fcx rather than returning
647 /// directly. coercion-cast is handled in check instead of here.
648 pub fn do_check(&self, fcx
: &FnCtxt
<'a
, 'tcx
>) -> Result
<CastKind
, CastError
> {
649 use rustc_middle
::ty
::cast
::CastTy
::*;
650 use rustc_middle
::ty
::cast
::IntTy
::*;
652 let (t_from
, t_cast
) = match (CastTy
::from_ty(self.expr_ty
), CastTy
::from_ty(self.cast_ty
))
654 (Some(t_from
), Some(t_cast
)) => (t_from
, t_cast
),
655 // Function item types may need to be reified before casts.
656 (None
, Some(t_cast
)) => {
657 match *self.expr_ty
.kind() {
659 // Attempt a coercion to a fn pointer type.
660 let f
= fcx
.normalize_associated_types_in(
662 self.expr_ty
.fn_sig(fcx
.tcx
),
664 let res
= fcx
.try_coerce(
667 fcx
.tcx
.mk_fn_ptr(f
),
670 if let Err(TypeError
::IntrinsicCast
) = res
{
671 return Err(CastError
::IllegalCast
);
674 return Err(CastError
::NonScalar
);
678 // Special case some errors for references, and check for
679 // array-ptr-casts. `Ref` is not a CastTy because the cast
680 // is split into a coercion to a pointer type, followed by
682 ty
::Ref(_
, inner_ty
, mutbl
) => {
683 return match t_cast
{
684 Int(_
) | Float
=> match *inner_ty
.kind() {
688 | ty
::Infer(ty
::InferTy
::IntVar(_
) | ty
::InferTy
::FloatVar(_
)) => {
689 Err(CastError
::NeedDeref
)
691 _
=> Err(CastError
::NeedViaPtr
),
695 self.check_ref_cast(fcx
, TypeAndMut { mutbl, ty: inner_ty }
, mt
)
697 _
=> Err(CastError
::NonScalar
),
700 _
=> return Err(CastError
::NonScalar
),
703 _
=> return Err(CastError
::NonScalar
),
706 match (t_from
, t_cast
) {
707 // These types have invariants! can't cast into them.
708 (_
, Int(CEnum
) | FnPtr
) => Err(CastError
::NonScalar
),
711 (_
, Int(Bool
)) => Err(CastError
::CastToBool
),
714 (Int(U(ty
::UintTy
::U8
)), Int(Char
)) => Ok(CastKind
::U8CharCast
), // u8-char-cast
715 (_
, Int(Char
)) => Err(CastError
::CastToChar
),
718 (Int(Bool
) | Int(CEnum
) | Int(Char
), Float
) => Err(CastError
::NeedViaInt
),
720 (Int(Bool
) | Int(CEnum
) | Int(Char
) | Float
, Ptr(_
)) | (Ptr(_
) | FnPtr
, Float
) => {
721 Err(CastError
::IllegalCast
)
725 (Ptr(m_e
), Ptr(m_c
)) => self.check_ptr_ptr_cast(fcx
, m_e
, m_c
), // ptr-ptr-cast
726 (Ptr(m_expr
), Int(_
)) => self.check_ptr_addr_cast(fcx
, m_expr
), // ptr-addr-cast
727 (FnPtr
, Int(_
)) => Ok(CastKind
::FnPtrAddrCast
),
730 (Int(_
), Ptr(mt
)) => self.check_addr_ptr_cast(fcx
, mt
), // addr-ptr-cast
731 (FnPtr
, Ptr(mt
)) => self.check_fptr_ptr_cast(fcx
, mt
),
734 (Int(CEnum
), Int(_
)) => {
735 self.cenum_impl_drop_lint(fcx
);
736 Ok(CastKind
::EnumCast
)
738 (Int(Char
) | Int(Bool
), Int(_
)) => Ok(CastKind
::PrimIntCast
),
740 (Int(_
) | Float
, Int(_
) | Float
) => Ok(CastKind
::NumericCast
),
744 fn check_ptr_ptr_cast(
746 fcx
: &FnCtxt
<'a
, 'tcx
>,
747 m_expr
: ty
::TypeAndMut
<'tcx
>,
748 m_cast
: ty
::TypeAndMut
<'tcx
>,
749 ) -> Result
<CastKind
, CastError
> {
750 debug
!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", m_expr
, m_cast
);
751 // ptr-ptr cast. vtables must match.
753 let expr_kind
= fcx
.pointer_kind(m_expr
.ty
, self.span
)?
;
754 let cast_kind
= fcx
.pointer_kind(m_cast
.ty
, self.span
)?
;
756 let cast_kind
= match cast_kind
{
757 // We can't cast if target pointer kind is unknown
758 None
=> return Err(CastError
::UnknownCastPtrKind
),
759 Some(cast_kind
) => cast_kind
,
762 // Cast to thin pointer is OK
763 if cast_kind
== PointerKind
::Thin
{
764 return Ok(CastKind
::PtrPtrCast
);
767 let expr_kind
= match expr_kind
{
768 // We can't cast to fat pointer if source pointer kind is unknown
769 None
=> return Err(CastError
::UnknownExprPtrKind
),
770 Some(expr_kind
) => expr_kind
,
773 // thin -> fat? report invalid cast (don't complain about vtable kinds)
774 if expr_kind
== PointerKind
::Thin
{
775 return Err(CastError
::SizedUnsizedCast
);
778 // vtable kinds must match
779 if cast_kind
== expr_kind
{
780 Ok(CastKind
::PtrPtrCast
)
782 Err(CastError
::DifferingKinds
)
786 fn check_fptr_ptr_cast(
788 fcx
: &FnCtxt
<'a
, 'tcx
>,
789 m_cast
: ty
::TypeAndMut
<'tcx
>,
790 ) -> Result
<CastKind
, CastError
> {
791 // fptr-ptr cast. must be to thin ptr
793 match fcx
.pointer_kind(m_cast
.ty
, self.span
)?
{
794 None
=> Err(CastError
::UnknownCastPtrKind
),
795 Some(PointerKind
::Thin
) => Ok(CastKind
::FnPtrPtrCast
),
796 _
=> Err(CastError
::IllegalCast
),
800 fn check_ptr_addr_cast(
802 fcx
: &FnCtxt
<'a
, 'tcx
>,
803 m_expr
: ty
::TypeAndMut
<'tcx
>,
804 ) -> Result
<CastKind
, CastError
> {
805 // ptr-addr cast. must be from thin ptr
807 match fcx
.pointer_kind(m_expr
.ty
, self.span
)?
{
808 None
=> Err(CastError
::UnknownExprPtrKind
),
809 Some(PointerKind
::Thin
) => Ok(CastKind
::PtrAddrCast
),
810 _
=> Err(CastError
::NeedViaThinPtr
),
816 fcx
: &FnCtxt
<'a
, 'tcx
>,
817 m_expr
: ty
::TypeAndMut
<'tcx
>,
818 m_cast
: ty
::TypeAndMut
<'tcx
>,
819 ) -> Result
<CastKind
, CastError
> {
820 // array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const
821 if m_expr
.mutbl
== hir
::Mutability
::Mut
|| m_cast
.mutbl
== hir
::Mutability
::Not
{
822 if let ty
::Array(ety
, _
) = m_expr
.ty
.kind() {
823 // Due to the limitations of LLVM global constants,
824 // region pointers end up pointing at copies of
825 // vector elements instead of the original values.
826 // To allow raw pointers to work correctly, we
827 // need to special-case obtaining a raw pointer
828 // from a region pointer to a vector.
830 // Coerce to a raw pointer so that we generate AddressOf in MIR.
831 let array_ptr_type
= fcx
.tcx
.mk_ptr(m_expr
);
832 fcx
.try_coerce(self.expr
, self.expr_ty
, array_ptr_type
, AllowTwoPhase
::No
)
833 .unwrap_or_else(|_
| {
835 "could not cast from reference to array to pointer to array ({:?} to {:?})",
841 // this will report a type mismatch if needed
842 fcx
.demand_eqtype(self.span
, ety
, m_cast
.ty
);
843 return Ok(CastKind
::ArrayPtrCast
);
847 Err(CastError
::IllegalCast
)
850 fn check_addr_ptr_cast(
852 fcx
: &FnCtxt
<'a
, 'tcx
>,
853 m_cast
: TypeAndMut
<'tcx
>,
854 ) -> Result
<CastKind
, CastError
> {
855 // ptr-addr cast. pointer must be thin.
856 match fcx
.pointer_kind(m_cast
.ty
, self.span
)?
{
857 None
=> Err(CastError
::UnknownCastPtrKind
),
858 Some(PointerKind
::Thin
) => Ok(CastKind
::AddrPtrCast
),
859 _
=> Err(CastError
::IllegalCast
),
863 fn try_coercion_cast(&self, fcx
: &FnCtxt
<'a
, 'tcx
>) -> Result
<(), ty
::error
::TypeError
<'_
>> {
864 match fcx
.try_coerce(self.expr
, self.expr_ty
, self.cast_ty
, AllowTwoPhase
::No
) {
866 Err(err
) => Err(err
),
870 fn cenum_impl_drop_lint(&self, fcx
: &FnCtxt
<'a
, 'tcx
>) {
871 if let ty
::Adt(d
, _
) = self.expr_ty
.kind() {
872 if d
.has_dtor(fcx
.tcx
) {
873 fcx
.tcx
.struct_span_lint_hir(
874 lint
::builtin
::CENUM_IMPL_DROP_CAST
,
879 "cannot cast enum `{}` into integer `{}` because it implements `Drop`",
880 self.expr_ty
, self.cast_ty
890 impl<'a
, 'tcx
> FnCtxt
<'a
, 'tcx
> {
891 fn type_is_known_to_be_sized_modulo_regions(&self, ty
: Ty
<'tcx
>, span
: Span
) -> bool
{
892 let lang_item
= self.tcx
.require_lang_item(LangItem
::Sized
, None
);
893 traits
::type_known_to_meet_bound_modulo_regions(self, self.param_env
, ty
, lang_item
, span
)