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_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, +) -> ::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) { + 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 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::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 @@ pub fn codegen_rvalue_operand( } } mir::CastKind::DynStar => { - let data = match operand.val { + let (lldata, llextra) = match operand.val { OperandValue::Ref(_, _, _) => todo!(), - OperandValue::Immediate(v) => v, - OperandValue::Pair(_, _) => todo!(), + OperandValue::Immediate(v) => (v, None), + OperandValue::Pair(v, l) => (v, Some(l)), }; - 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::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 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 @@ pub fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result { (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 @@ fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'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 @@ fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceRe Ok(coercion) } + fn coerce_dyn_star( + &self, + a: Ty<'tcx>, + b: Ty<'tcx>, + predicates: &'tcx ty::List>>, + 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( &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 @@ fn check_expr_cast( } 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 @@ fn check_expr_cast( 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 @@ fn walk_adjustment(&mut self, expr: &hir::Expr<'_>) { 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 @@ fn cat_expr_adjusted_with( 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 @@ pub fn is_safe_to_remove(&self) -> bool { // While the model is undecided, we should be conservative. See // Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false, - Rvalue::Cast(CastKind::DynStar, _, _) => false, Rvalue::Use(_) | Rvalue::CopyForDeref(_) @@ -1841,7 +1840,8 @@ pub fn is_safe_to_remove(&self) -> bool { | 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 @@ fn apply_adjustment( 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 } diff --git a/src/test/ui/dyn-star/auxiliary/dyn-star-foreign.rs b/src/test/ui/dyn-star/auxiliary/dyn-star-foreign.rs new file mode 100644 index 00000000000..7673c793678 --- /dev/null +++ b/src/test/ui/dyn-star/auxiliary/dyn-star-foreign.rs @@ -0,0 +1,10 @@ +#![feature(dyn_star)] +#![allow(incomplete_features)] + +use std::fmt::Display; + +pub fn require_dyn_star_display(_: dyn* Display) {} + +fn works_locally() { + require_dyn_star_display(1usize); +} diff --git a/src/test/ui/dyn-star/const.rs b/src/test/ui/dyn-star/const.rs index e49caf649f8..67e3ab7ab35 100644 --- a/src/test/ui/dyn-star/const.rs +++ b/src/test/ui/dyn-star/const.rs @@ -6,7 +6,7 @@ fn make_dyn_star() { let i = 42usize; - let dyn_i: dyn* Debug = i as dyn* Debug; + let dyn_i: dyn* Debug = i; } fn main() { diff --git a/src/test/ui/dyn-star/drop.rs b/src/test/ui/dyn-star/drop.rs index 46b232f3dd3..1478498c0a9 100644 --- a/src/test/ui/dyn-star/drop.rs +++ b/src/test/ui/dyn-star/drop.rs @@ -15,7 +15,7 @@ fn drop(&mut self) { } fn make_dyn_star(i: Foo) { - let _dyn_i: dyn* Debug = i as dyn* Debug; + let _dyn_i: dyn* Debug = i; } fn main() { diff --git a/src/test/ui/dyn-star/error.rs b/src/test/ui/dyn-star/error.rs index 33eff80a5fe..d8261387efa 100644 --- a/src/test/ui/dyn-star/error.rs +++ b/src/test/ui/dyn-star/error.rs @@ -7,7 +7,7 @@ trait Foo {} fn make_dyn_star() { let i = 42; - let dyn_i: dyn* Foo = i as dyn* Foo; //~ ERROR trait bound `{integer}: Foo` is not satisfied + let dyn_i: dyn* Foo = i; //~ ERROR trait bound `{integer}: Foo` is not satisfied } fn main() {} diff --git a/src/test/ui/dyn-star/error.stderr b/src/test/ui/dyn-star/error.stderr index d612ccc630e..ae54b9ca707 100644 --- a/src/test/ui/dyn-star/error.stderr +++ b/src/test/ui/dyn-star/error.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `{integer}: Foo` is not satisfied --> $DIR/error.rs:10:27 | -LL | let dyn_i: dyn* Foo = i as dyn* Foo; +LL | let dyn_i: dyn* Foo = i; | ^ the trait `Foo` is not implemented for `{integer}` error: aborting due to previous error diff --git a/src/test/ui/dyn-star/make-dyn-star.rs b/src/test/ui/dyn-star/make-dyn-star.rs index 708ffa25d6f..e5255a64ba1 100644 --- a/src/test/ui/dyn-star/make-dyn-star.rs +++ b/src/test/ui/dyn-star/make-dyn-star.rs @@ -5,9 +5,14 @@ use std::fmt::Debug; fn make_dyn_star(i: usize) { + let _dyn_i: dyn* Debug = i; +} + +fn make_dyn_star_explicit(i: usize) { let _dyn_i: dyn* Debug = i as dyn* Debug; } fn main() { make_dyn_star(42); + make_dyn_star_explicit(42); } diff --git a/src/test/ui/dyn-star/method.rs b/src/test/ui/dyn-star/method.rs index d04958ca2aa..5a77640f0d9 100644 --- a/src/test/ui/dyn-star/method.rs +++ b/src/test/ui/dyn-star/method.rs @@ -1,4 +1,5 @@ // run-pass + #![feature(dyn_star)] #![allow(incomplete_features)] @@ -17,7 +18,7 @@ fn invoke_dyn_star(i: dyn* Foo) -> usize { } fn make_and_invoke_dyn_star(i: usize) -> usize { - let dyn_i: dyn* Foo = i as dyn* Foo; + let dyn_i: dyn* Foo = i; invoke_dyn_star(dyn_i) } diff --git a/src/test/ui/dyn-star/no-implicit-dyn-star.rs b/src/test/ui/dyn-star/no-implicit-dyn-star.rs new file mode 100644 index 00000000000..d9470e28417 --- /dev/null +++ b/src/test/ui/dyn-star/no-implicit-dyn-star.rs @@ -0,0 +1,8 @@ +// aux-build:dyn-star-foreign.rs + +extern crate dyn_star_foreign; + +fn main() { + dyn_star_foreign::require_dyn_star_display(1usize); + //~^ ERROR mismatched types +} diff --git a/src/test/ui/dyn-star/no-implicit-dyn-star.stderr b/src/test/ui/dyn-star/no-implicit-dyn-star.stderr new file mode 100644 index 00000000000..e7c5918629b --- /dev/null +++ b/src/test/ui/dyn-star/no-implicit-dyn-star.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/no-implicit-dyn-star.rs:6:48 + | +LL | dyn_star_foreign::require_dyn_star_display(1usize); + | ------------------------------------------ ^^^^^^ expected trait object `dyn std::fmt::Display`, found `usize` + | | + | arguments to this function are incorrect + | + = note: expected trait object `(dyn* std::fmt::Display + 'static)` + found type `usize` +note: function defined here + --> $DIR/auxiliary/dyn-star-foreign.rs:6:8 + | +LL | pub fn require_dyn_star_display(_: dyn* Display) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/dyn-star/upcast.rs b/src/test/ui/dyn-star/upcast.rs new file mode 100644 index 00000000000..cee76ada7df --- /dev/null +++ b/src/test/ui/dyn-star/upcast.rs @@ -0,0 +1,33 @@ +// run-pass + +#![feature(dyn_star, trait_upcasting)] +#![allow(incomplete_features)] + +trait Foo: Bar { + fn hello(&self); +} + +trait Bar { + fn world(&self); +} + +struct W(usize); + +impl Foo for W { + fn hello(&self) { + println!("hello!"); + } +} + +impl Bar for W { + fn world(&self) { + println!("world!"); + } +} + +fn main() { + let w: dyn* Foo = W(0); + w.hello(); + let w: dyn* Bar = w; + w.world(); +} diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs index b567d92230b..102f7541c8c 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs @@ -1,15 +1,16 @@ use rustc_hir::Expr; -use rustc_hir_analysis::check::{ - cast::{self, CastCheckResult}, - FnCtxt, Inherited, -}; +use rustc_hir_analysis::check::{cast, FnCtxt, Inherited}; use rustc_lint::LateContext; use rustc_middle::ty::{cast::CastKind, Ty}; use rustc_span::DUMMY_SP; // check if the component types of the transmuted collection and the result have different ABI, // size or alignment -pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx>, to: Ty<'tcx>) -> bool { +pub(super) fn is_layout_incompatible<'tcx>( + cx: &LateContext<'tcx>, + from: Ty<'tcx>, + to: Ty<'tcx>, +) -> bool { if let Ok(from) = cx.tcx.try_normalize_erasing_regions(cx.param_env, from) && let Ok(to) = cx.tcx.try_normalize_erasing_regions(cx.param_env, to) && let Ok(from_layout) = cx.tcx.layout_of(cx.param_env.and(from)) @@ -32,7 +33,9 @@ pub(super) fn can_be_expressed_as_pointer_cast<'tcx>( from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, ) -> bool { - use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast}; + use CastKind::{ + AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast, + }; matches!( check_cast(cx, e, from_ty, to_ty), Some(PtrPtrCast | PtrAddrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) @@ -43,7 +46,12 @@ pub(super) fn can_be_expressed_as_pointer_cast<'tcx>( /// the cast. In certain cases, including some invalid casts from array references /// to pointers, this may cause additional errors to be emitted and/or ICE error /// messages. This function will panic if that occurs. -fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> Option { +fn check_cast<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + from_ty: Ty<'tcx>, + to_ty: Ty<'tcx>, +) -> Option { let hir_id = e.hir_id; let local_def_id = hir_id.owner.def_id; @@ -51,12 +59,9 @@ fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx> let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, hir_id); // If we already have errors, we can't be sure we can pointer cast. - assert!( - !fn_ctxt.errors_reported_since_creation(), - "Newly created FnCtxt contained errors" - ); + assert!(!fn_ctxt.errors_reported_since_creation(), "Newly created FnCtxt contained errors"); - if let CastCheckResult::Deferred(check) = cast::check_cast( + if let Ok(check) = cast::CastCheck::new( &fn_ctxt, e, from_ty, to_ty, // We won't show any error to the user, so we don't care what the span is here. DUMMY_SP, DUMMY_SP,