about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs64
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs27
-rw-r--r--compiler/rustc_hir_analysis/src/check/cast.rs79
-rw-r--r--compiler/rustc_hir_analysis/src/check/coercion.rs60
-rw-r--r--compiler/rustc_hir_analysis/src/check/expr.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/expr_use_visitor.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/mem_categorization.rs3
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs4
-rw-r--r--compiler/rustc_middle/src/ty/adjustment.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs1
10 files changed, 135 insertions, 119 deletions
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index cb5436fd61a..0ca6408aab9 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -38,7 +38,7 @@ use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::Symbol;
 use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType};
-use rustc_target::abi::{Align, VariantIdx};
+use rustc_target::abi::{Align, Size, VariantIdx};
 
 use std::collections::BTreeSet;
 use std::convert::TryFrom;
@@ -150,7 +150,12 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         (&ty::Array(_, len), &ty::Slice(_)) => {
             cx.const_usize(len.eval_usize(cx.tcx(), ty::ParamEnv::reveal_all()))
         }
-        (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
+        (
+            &ty::Dynamic(ref data_a, _, src_dyn_kind),
+            &ty::Dynamic(ref data_b, _, target_dyn_kind),
+        ) => {
+            assert_eq!(src_dyn_kind, target_dyn_kind);
+
             let old_info =
                 old_info.expect("unsized_info: missing old info for trait upcasting coercion");
             if data_a.principal_def_id() == data_b.principal_def_id() {
@@ -166,11 +171,7 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
             if let Some(entry_idx) = vptr_entry_idx {
                 let ptr_ty = cx.type_i8p();
                 let ptr_align = cx.tcx().data_layout.pointer_align.abi;
-                let vtable_ptr_ty = cx.scalar_pair_element_backend_type(
-                    cx.layout_of(cx.tcx().mk_mut_ptr(target)),
-                    1,
-                    true,
-                );
+                let vtable_ptr_ty = vtable_ptr_ty(cx, target, target_dyn_kind);
                 let llvtable = bx.pointercast(old_info, bx.type_ptr_to(ptr_ty));
                 let gep = bx.inbounds_gep(
                     ptr_ty,
@@ -186,18 +187,32 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                 old_info
             }
         }
-        (_, &ty::Dynamic(ref data, ..)) => {
-            let vtable_ptr_ty = cx.scalar_pair_element_backend_type(
-                cx.layout_of(cx.tcx().mk_mut_ptr(target)),
-                1,
-                true,
-            );
+        (_, &ty::Dynamic(ref data, _, target_dyn_kind)) => {
+            let vtable_ptr_ty = vtable_ptr_ty(cx, target, target_dyn_kind);
             cx.const_ptrcast(meth::get_vtable(cx, source, data.principal()), vtable_ptr_ty)
         }
         _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target),
     }
 }
 
+// Returns the vtable pointer type of a `dyn` or `dyn*` type
+fn vtable_ptr_ty<'tcx, Cx: CodegenMethods<'tcx>>(
+    cx: &Cx,
+    target: Ty<'tcx>,
+    kind: ty::DynKind,
+) -> <Cx as BackendTypes>::Type {
+    cx.scalar_pair_element_backend_type(
+        cx.layout_of(match kind {
+            // vtable is the second field of `*mut dyn Trait`
+            ty::Dyn => cx.tcx().mk_mut_ptr(target),
+            // vtable is the second field of `dyn* Trait`
+            ty::DynStar => target,
+        }),
+        1,
+        true,
+    )
+}
+
 /// Coerces `src` to `dst_ty`. `src_ty` must be a pointer.
 pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     bx: &mut Bx,
@@ -247,6 +262,29 @@ pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     }
 }
 
+/// Coerces `src` to `dst_ty` which is guaranteed to be a `dyn*` type.
+pub fn cast_to_dyn_star<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
+    bx: &mut Bx,
+    src: Bx::Value,
+    src_ty_and_layout: TyAndLayout<'tcx>,
+    dst_ty: Ty<'tcx>,
+    old_info: Option<Bx::Value>,
+) -> (Bx::Value, Bx::Value) {
+    debug!("cast_to_dyn_star: {:?} => {:?}", src_ty_and_layout.ty, dst_ty);
+    assert!(
+        matches!(dst_ty.kind(), ty::Dynamic(_, _, ty::DynStar)),
+        "destination type must be a dyn*"
+    );
+    // FIXME(dyn-star): this is probably not the best way to check if this is
+    // a pointer, and really we should ensure that the value is a suitable
+    // pointer earlier in the compilation process.
+    let src = match src_ty_and_layout.pointee_info_at(bx.cx(), Size::ZERO) {
+        Some(_) => bx.ptrtoint(src, bx.cx().type_isize()),
+        None => bx.bitcast(src, bx.type_isize()),
+    };
+    (src, unsized_info(bx, src_ty_and_layout.ty, dst_ty, old_info))
+}
+
 /// Coerces `src`, which is a reference to a value of type `src_ty`,
 /// to a value of type `dst_ty`, and stores the result in `dst`.
 pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 4ed99df1e81..4aab31fbfe7 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -4,7 +4,6 @@ use super::{FunctionCx, LocalRef};
 
 use crate::base;
 use crate::common::{self, IntPredicate};
-use crate::meth::get_vtable;
 use crate::traits::*;
 use crate::MemFlags;
 
@@ -14,7 +13,6 @@ use rustc_middle::ty::cast::{CastTy, IntTy};
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
 use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt};
 use rustc_span::source_map::{Span, DUMMY_SP};
-use rustc_target::abi::Size;
 
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     #[instrument(level = "trace", skip(self, bx))]
@@ -274,27 +272,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         }
                     }
                     mir::CastKind::DynStar => {
-                        let data = match operand.val {
+                        let (lldata, llextra) = match operand.val {
                             OperandValue::Ref(_, _, _) => todo!(),
-                            OperandValue::Immediate(v) => v,
-                            OperandValue::Pair(_, _) => todo!(),
-                        };
-                        let trait_ref =
-                            if let ty::Dynamic(data, _, ty::DynStar) = cast.ty.kind() {
-                                data.principal()
-                            } else {
-                                bug!("Only valid to do a DynStar cast into a DynStar type")
-                            };
-                        let vtable = get_vtable(bx.cx(), source.ty(self.mir, bx.tcx()), trait_ref);
-                        let vtable = bx.pointercast(vtable, bx.cx().type_ptr_to(bx.cx().type_isize()));
-                        // FIXME(dyn-star): this is probably not the best way to check if this is
-                        // a pointer, and really we should ensure that the value is a suitable
-                        // pointer earlier in the compilation process.
-                        let data = match operand.layout.pointee_info_at(bx.cx(), Size::ZERO) {
-                            Some(_) => bx.ptrtoint(data, bx.cx().type_isize()),
-                            None => data,
+                            OperandValue::Immediate(v) => (v, None),
+                            OperandValue::Pair(v, l) => (v, Some(l)),
                         };
-                        OperandValue::Pair(data, vtable)
+                        let (lldata, llextra) =
+                            base::cast_to_dyn_star(&mut bx, lldata, operand.layout, cast.ty, llextra);
+                        OperandValue::Pair(lldata, llextra)
                     }
                     mir::CastKind::Pointer(
                         PointerCast::MutToConstPointer | PointerCast::ArrayToPointer,
diff --git a/compiler/rustc_hir_analysis/src/check/cast.rs b/compiler/rustc_hir_analysis/src/check/cast.rs
index 01badc133c9..51abdd2e059 100644
--- a/compiler/rustc_hir_analysis/src/check/cast.rs
+++ b/compiler/rustc_hir_analysis/src/check/cast.rs
@@ -35,13 +35,12 @@ use crate::type_error_struct;
 use hir::def_id::LOCAL_CRATE;
 use rustc_errors::{struct_span_err, Applicability, DelayDm, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
-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, Binder, Ty, TypeAndMut, TypeVisitable, VariantDef};
+use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef};
 use rustc_session::lint;
 use rustc_session::Session;
 use rustc_span::symbol::sym;
@@ -204,76 +203,8 @@ 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> {
-    fn new(
+    pub fn new(
         fcx: &FnCtxt<'a, 'tcx>,
         expr: &'tcx hir::Expr<'tcx>,
         expr_ty: Ty<'tcx>,
@@ -934,11 +865,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
 
             (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),
+            (_, DynStar) | (DynStar, _) => bug!("should be handled by `try_coerce`"),
         }
     }
 
diff --git a/compiler/rustc_hir_analysis/src/check/coercion.rs b/compiler/rustc_hir_analysis/src/check/coercion.rs
index cf87fe3c510..faa6c6d9356 100644
--- a/compiler/rustc_hir_analysis/src/check/coercion.rs
+++ b/compiler/rustc_hir_analysis/src/check/coercion.rs
@@ -216,6 +216,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             ty::Ref(r_b, _, mutbl_b) => {
                 return self.coerce_borrowed_pointer(a, b, r_b, mutbl_b);
             }
+            ty::Dynamic(predicates, region, ty::DynStar) if self.tcx.features().dyn_star => {
+                return self.coerce_dyn_star(a, b, predicates, region);
+            }
             _ => {}
         }
 
@@ -745,6 +748,63 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         Ok(coercion)
     }
 
+    fn coerce_dyn_star(
+        &self,
+        a: Ty<'tcx>,
+        b: Ty<'tcx>,
+        predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
+        b_region: ty::Region<'tcx>,
+    ) -> CoerceResult<'tcx> {
+        if !self.tcx.features().dyn_star {
+            return Err(TypeError::Mismatch);
+        }
+
+        if let ty::Dynamic(a_data, _, _) = a.kind()
+            && let ty::Dynamic(b_data, _, _) = b.kind()
+        {
+            if a_data.principal_def_id() == b_data.principal_def_id() {
+                return self.unify_and(a, b, |_| vec![]);
+            } else if !self.tcx().features().trait_upcasting {
+                let mut err = feature_err(
+                    &self.tcx.sess.parse_sess,
+                    sym::trait_upcasting,
+                    self.cause.span,
+                    &format!(
+                        "cannot cast `{a}` to `{b}`, trait upcasting coercion is experimental"
+                    ),
+                );
+                err.emit();
+            }
+        }
+
+        // Check the obligations of the cast -- for example, when casting
+        // `usize` to `dyn* Clone + 'static`:
+        let obligations = predicates
+            .iter()
+            .map(|predicate| {
+                // 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).
+                let predicate = predicate.with_self_ty(self.tcx, a);
+                Obligation::new(self.cause.clone(), self.param_env, predicate)
+            })
+            // Enforce the region bound (e.g., `usize: 'static`, in our example).
+            .chain([Obligation::new(
+                self.cause.clone(),
+                self.param_env,
+                self.tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::TypeOutlives(
+                    ty::OutlivesPredicate(a, b_region),
+                ))),
+            )])
+            .collect();
+
+        Ok(InferOk {
+            value: (vec![Adjustment { kind: Adjust::DynStar, target: b }], b),
+            obligations,
+        })
+    }
+
     fn coerce_from_safe_fn<F, G>(
         &self,
         a: Ty<'tcx>,
diff --git a/compiler/rustc_hir_analysis/src/check/expr.rs b/compiler/rustc_hir_analysis/src/check/expr.rs
index 34c25784597..71c6da862c9 100644
--- a/compiler/rustc_hir_analysis/src/check/expr.rs
+++ b/compiler/rustc_hir_analysis/src/check/expr.rs
@@ -3,7 +3,7 @@
 //! See `mod.rs` for more context on type checking in general.
 
 use crate::astconv::AstConv as _;
-use crate::check::cast::{self, CastCheckResult};
+use crate::check::cast;
 use crate::check::coercion::CoerceMany;
 use crate::check::fatally_break_rust;
 use crate::check::method::SelfSource;
@@ -1270,9 +1270,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         } else {
             // Defer other checks until we're done type checking.
             let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
-            match cast::check_cast(self, e, t_expr, t_cast, t.span, expr.span) {
-                CastCheckResult::Ok => t_cast,
-                CastCheckResult::Deferred(cast_check) => {
+            match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) {
+                Ok(cast_check) => {
                     debug!(
                         "check_expr_cast: deferring cast from {:?} to {:?}: {:?}",
                         t_cast, t_expr, cast_check,
@@ -1280,7 +1279,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     deferred_cast_checks.push(cast_check);
                     t_cast
                 }
-                CastCheckResult::Err(ErrorGuaranteed { .. }) => self.tcx.ty_error(),
+                Err(_) => self.tcx.ty_error(),
             }
         }
     }
diff --git a/compiler/rustc_hir_analysis/src/expr_use_visitor.rs b/compiler/rustc_hir_analysis/src/expr_use_visitor.rs
index cbc3769901d..039c653e5bc 100644
--- a/compiler/rustc_hir_analysis/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_analysis/src/expr_use_visitor.rs
@@ -583,7 +583,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
         for adjustment in adjustments {
             debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
             match adjustment.kind {
-                adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) => {
+                adjustment::Adjust::NeverToAny
+                | adjustment::Adjust::Pointer(_)
+                | adjustment::Adjust::DynStar => {
                     // Creating a closure/fn-pointer or unsizing consumes
                     // the input and stores it into the resulting rvalue.
                     self.delegate_consume(&place_with_id, place_with_id.hir_id);
diff --git a/compiler/rustc_hir_analysis/src/mem_categorization.rs b/compiler/rustc_hir_analysis/src/mem_categorization.rs
index b62c5b5e077..362f1c34300 100644
--- a/compiler/rustc_hir_analysis/src/mem_categorization.rs
+++ b/compiler/rustc_hir_analysis/src/mem_categorization.rs
@@ -292,7 +292,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
 
             adjustment::Adjust::NeverToAny
             | adjustment::Adjust::Pointer(_)
-            | adjustment::Adjust::Borrow(_) => {
+            | adjustment::Adjust::Borrow(_)
+            | adjustment::Adjust::DynStar => {
                 // Result is an rvalue.
                 Ok(self.cat_rvalue(expr.hir_id, expr.span, target))
             }
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index d4258151ff3..c022ea9e5b4 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -1824,7 +1824,6 @@ impl<'tcx> Rvalue<'tcx> {
             // While the model is undecided, we should be conservative. See
             // <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html>
             Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false,
-            Rvalue::Cast(CastKind::DynStar, _, _) => false,
 
             Rvalue::Use(_)
             | Rvalue::CopyForDeref(_)
@@ -1841,7 +1840,8 @@ impl<'tcx> Rvalue<'tcx> {
                 | CastKind::FnPtrToPtr
                 | CastKind::PtrToPtr
                 | CastKind::Pointer(_)
-                | CastKind::PointerFromExposedAddress,
+                | CastKind::PointerFromExposedAddress
+                | CastKind::DynStar,
                 _,
                 _,
             )
diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs
index b809f176760..4682ac96b52 100644
--- a/compiler/rustc_middle/src/ty/adjustment.rs
+++ b/compiler/rustc_middle/src/ty/adjustment.rs
@@ -101,6 +101,9 @@ pub enum Adjust<'tcx> {
     Borrow(AutoBorrow<'tcx>),
 
     Pointer(PointerCast),
+
+    /// Cast into a dyn* object.
+    DynStar,
 }
 
 /// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)`
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index bcf2ed68172..c7a7c3e3fa8 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -159,6 +159,7 @@ impl<'tcx> Cx<'tcx> {
             Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => {
                 ExprKind::AddressOf { mutability, arg: self.thir.exprs.push(expr) }
             }
+            Adjust::DynStar => ExprKind::Cast { source: self.thir.exprs.push(expr) },
         };
 
         Expr { temp_lifetime, ty: adjustment.target, span, kind }