diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:03:36 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:03:36 +0000 |
commit | 17d40c6057c88f4c432b0d7bac88e1b84cb7e67f (patch) | |
tree | 3f66c4a5918660bb8a758ab6cda5ff8ee4f6cdcd /compiler/rustc_typeck/src/check/cast.rs | |
parent | Adding upstream version 1.64.0+dfsg1. (diff) | |
download | rustc-f7f0cc2a5d72e2c61c1f6900e70eec992bea4273.tar.xz rustc-f7f0cc2a5d72e2c61c1f6900e70eec992bea4273.zip |
Adding upstream version 1.65.0+dfsg1.upstream/1.65.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | compiler/rustc_typeck/src/check/cast.rs | 121 |
1 files changed, 106 insertions, 15 deletions
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 7aaddc2bd..81a979865 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -32,30 +32,33 @@ use super::FnCtxt; use crate::hir::def_id::DefId; use crate::type_error_struct; +use hir::def_id::LOCAL_CRATE; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; -use rustc_hir::lang_items::LangItem; +use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode}; use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::cast::{CastKind, CastTy}; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable}; +use rustc_middle::ty::{self, Binder, Ty, TypeAndMut, TypeVisitable, VariantDef}; use rustc_session::lint; use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_trait_selection::infer::InferCtxtExt; -use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::report_object_safety_error; /// Reifies a cast check to be checked once we have full type information for /// a function context. #[derive(Debug)] pub struct CastCheck<'tcx> { + /// The expression whose value is being casted expr: &'tcx hir::Expr<'tcx>, + /// The source type for the cast expression expr_ty: Ty<'tcx>, expr_span: Span, + /// The target type. That is, the type we are casting to. cast_ty: Ty<'tcx>, cast_span: Span, span: Span, @@ -96,13 +99,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Err(reported); } - if self.type_is_known_to_be_sized_modulo_regions(t, span) { + if self.type_is_sized_modulo_regions(self.param_env, t, span) { return Ok(Some(PointerKind::Thin)); } Ok(match *t.kind() { ty::Slice(_) | ty::Str => Some(PointerKind::Length), - ty::Dynamic(ref tty, ..) => Some(PointerKind::VTable(tty.principal_def_id())), + ty::Dynamic(ref tty, _, ty::Dyn) => Some(PointerKind::VTable(tty.principal_def_id())), ty::Adt(def, substs) if def.is_struct() => match def.non_enum_variant().fields.last() { None => Some(PointerKind::Thin), Some(f) => { @@ -139,6 +142,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::Generator(..) | ty::Adt(..) | ty::Never + | ty::Dynamic(_, _, ty::DynStar) | ty::Error(_) => { let reported = self .tcx @@ -173,6 +177,7 @@ pub enum CastError { /// or "a length". If this argument is None, then the metadata is unknown, for example, /// when we're typechecking a type parameter with a ?Sized bound. IntToFatCast(Option<&'static str>), + ForeignNonExhaustiveAdt, } impl From<ErrorGuaranteed> for CastError { @@ -199,8 +204,76 @@ fn make_invalid_casting_error<'a, 'tcx>( ) } +pub enum CastCheckResult<'tcx> { + Ok, + Deferred(CastCheck<'tcx>), + Err(ErrorGuaranteed), +} + +pub fn check_cast<'tcx>( + fcx: &FnCtxt<'_, 'tcx>, + expr: &'tcx hir::Expr<'tcx>, + expr_ty: Ty<'tcx>, + cast_ty: Ty<'tcx>, + cast_span: Span, + span: Span, +) -> CastCheckResult<'tcx> { + if cast_ty.is_dyn_star() { + check_dyn_star_cast(fcx, expr, expr_ty, cast_ty) + } else { + match CastCheck::new(fcx, expr, expr_ty, cast_ty, cast_span, span) { + Ok(check) => CastCheckResult::Deferred(check), + Err(e) => CastCheckResult::Err(e), + } + } +} + +fn check_dyn_star_cast<'tcx>( + fcx: &FnCtxt<'_, 'tcx>, + expr: &'tcx hir::Expr<'tcx>, + expr_ty: Ty<'tcx>, + cast_ty: Ty<'tcx>, +) -> CastCheckResult<'tcx> { + // Find the bounds in the dyn*. For eaxmple, if we have + // + // let x = 22_usize as dyn* (Clone + Debug + 'static) + // + // this would return `existential_predicates = [?Self: Clone, ?Self: Debug]` and `region = 'static`. + let (existential_predicates, region) = match cast_ty.kind() { + ty::Dynamic(predicates, region, ty::DynStar) => (predicates, region), + _ => panic!("Invalid dyn* cast_ty"), + }; + + let cause = ObligationCause::new( + expr.span, + fcx.body_id, + // FIXME(dyn-star): Use a better obligation cause code + ObligationCauseCode::MiscObligation, + ); + + // For each existential predicate (e.g., `?Self: Clone`) substitute + // the type of the expression (e.g., `usize` in our example above) + // and then require that the resulting predicate (e.g., `usize: Clone`) + // holds (it does). + for existential_predicate in existential_predicates.iter() { + let predicate = existential_predicate.with_self_ty(fcx.tcx, expr_ty); + fcx.register_predicate(Obligation::new(cause.clone(), fcx.param_env, predicate)); + } + + // Enforce the region bound `'static` (e.g., `usize: 'static`, in our example). + fcx.register_predicate(Obligation::new( + cause, + fcx.param_env, + fcx.tcx.mk_predicate(Binder::dummy(ty::PredicateKind::TypeOutlives( + ty::OutlivesPredicate(expr_ty, *region), + ))), + )); + + CastCheckResult::Ok +} + impl<'a, 'tcx> CastCheck<'tcx> { - pub fn new( + fn new( fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr<'tcx>, expr_ty: Ty<'tcx>, @@ -215,7 +288,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { // cases now. We do a more thorough check at the end, once // inference is more completely known. match cast_ty.kind() { - ty::Dynamic(..) | ty::Slice(..) => { + ty::Dynamic(_, _, ty::Dyn) | ty::Slice(..) => { let reported = check.report_cast_to_unsized_type(fcx); Err(reported) } @@ -591,6 +664,17 @@ impl<'a, 'tcx> CastCheck<'tcx> { } err.emit(); } + CastError::ForeignNonExhaustiveAdt => { + make_invalid_casting_error( + fcx.tcx.sess, + self.span, + self.expr_ty, + self.cast_ty, + fcx, + ) + .note("cannot cast an enum with a non-exhaustive variant when it's defined in another crate") + .emit(); + } } } @@ -692,7 +776,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty); - if !fcx.type_is_known_to_be_sized_modulo_regions(self.cast_ty, self.span) + if !fcx.type_is_sized_modulo_regions(fcx.param_env, self.cast_ty, self.span) && !self.cast_ty.has_infer_types() { self.report_cast_to_unsized_type(fcx); @@ -789,6 +873,14 @@ impl<'a, 'tcx> CastCheck<'tcx> { _ => return Err(CastError::NonScalar), }; + if let ty::Adt(adt_def, _) = *self.expr_ty.kind() { + if adt_def.did().krate != LOCAL_CRATE { + if adt_def.variants().iter().any(VariantDef::is_field_list_non_exhaustive) { + return Err(CastError::ForeignNonExhaustiveAdt); + } + } + } + match (t_from, t_cast) { // These types have invariants! can't cast into them. (_, Int(CEnum) | FnPtr) => Err(CastError::NonScalar), @@ -835,6 +927,12 @@ impl<'a, 'tcx> CastCheck<'tcx> { (Int(Char) | Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast), (Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast), + + // FIXME(dyn-star): this needs more conditions... + (_, DynStar) => Ok(CastKind::DynStarCast), + + // FIXME(dyn-star): do we want to allow dyn* upcasting or other casts? + (DynStar, _) => Err(CastError::IllegalCast), } } @@ -1063,10 +1161,3 @@ impl<'a, 'tcx> CastCheck<'tcx> { ); } } - -impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - fn type_is_known_to_be_sized_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool { - let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); - traits::type_known_to_meet_bound_modulo_regions(self, self.param_env, ty, lang_item, span) - } -} |