From ef5acdecebb48a02cb34d19fa17d1bd59e41a4d3 Mon Sep 17 00:00:00 2001 From: Mathias Blikstad Date: Tue, 8 Jan 2019 22:14:04 +0100 Subject: [PATCH] RFC 2027: "first draft" of implementation These are a squashed series of commits. --- src/librustc/infer/error_reporting/mod.rs | 24 +++++-- src/librustc/traits/error_reporting.rs | 32 ++++----- src/librustc/traits/mod.rs | 3 + src/librustc/traits/select.rs | 8 ++- src/librustc/traits/structural_impls.rs | 4 ++ src/librustc/ty/error.rs | 3 +- src/librustc/ty/structural_impls.rs | 2 + src/librustc/ty/wf.rs | 25 ++++--- src/librustc_errors/diagnostic.rs | 26 +++++++ src/librustc_errors/diagnostic_builder.rs | 5 ++ src/librustc_typeck/astconv.rs | 3 +- src/librustc_typeck/check/cast.rs | 43 +++++++++--- src/librustc_typeck/check/coercion.rs | 31 ++++++--- src/librustc_typeck/coherence/mod.rs | 5 +- src/libsyntax/feature_gate/active.rs | 3 + src/libsyntax_pos/symbol.rs | 1 + .../coherence-unsafe-trait-object-impl.rs | 18 +++++ .../coherence-unsafe-trait-object-impl.stderr | 12 ++++ ...eature-gate-exhaustive-patterns.nll.stderr | 16 ----- .../feature-gate-object_safe_for_dispatch.rs | 41 +++++++++++ ...ature-gate-object_safe_for_dispatch.stderr | 46 +++++++++++++ src/test/ui/issues/issue-19538.stderr | 1 + src/test/ui/issues/issue-20692.stderr | 1 + src/test/ui/issues/issue-38604.stderr | 1 + ...> kindck-inherited-copy-bound.curr.stderr} | 7 +- ...copy-bound.object_safe_for_dispatch.stderr | 25 +++++++ .../ui/kindck/kindck-inherited-copy-bound.rs | 11 ++- ...ject-safety-associated-consts.curr.stderr} | 2 +- ...ted-consts.object_safe_for_dispatch.stderr | 15 ++++ .../object-safety-associated-consts.rs | 6 +- ...err => object-safety-generics.curr.stderr} | 4 +- ...y-generics.object_safe_for_dispatch.stderr | 27 ++++++++ .../object-safety/object-safety-generics.rs | 10 ++- ...> object-safety-mentions-Self.curr.stderr} | 8 +-- ...tions-Self.object_safe_for_dispatch.stderr | 27 ++++++++ .../object-safety-mentions-Self.rs | 20 ++++-- .../object-safety-no-static.curr.stderr | 12 ++++ ...-no-static.object_safe_for_dispatch.stderr | 15 ++++ .../object-safety/object-safety-no-static.rs | 16 ++++- ...derr => object-safety-sized-2.curr.stderr} | 2 +- ...ty-sized-2.object_safe_for_dispatch.stderr | 13 ++++ .../ui/object-safety/object-safety-sized-2.rs | 9 ++- ...stderr => object-safety-sized.curr.stderr} | 2 +- ...fety-sized.object_safe_for_dispatch.stderr | 13 ++++ .../ui/object-safety/object-safety-sized.rs | 7 +- .../downcast-unsafe-trait-objects.rs | 23 +++++++ .../manual-self-impl-for-unsafe-obj.rs | 69 +++++++++++++++++++ .../static-dispatch-unsafe-object.rs | 37 ++++++++++ ...ary-self-types-not-object-safe.curr.stderr | 24 +++++++ ...bject-safe.object_safe_for_dispatch.stderr | 15 ++++ .../arbitrary-self-types-not-object-safe.rs | 8 ++- src/test/ui/traits/trait-object-safety.stderr | 1 + src/test/ui/traits/trait-test-2.stderr | 1 + .../ui/wf/wf-convert-unsafe-trait-obj-box.rs | 18 +++++ .../wf/wf-convert-unsafe-trait-obj-box.stderr | 33 +++++++++ src/test/ui/wf/wf-convert-unsafe-trait-obj.rs | 18 +++++ .../ui/wf/wf-convert-unsafe-trait-obj.stderr | 33 +++++++++ src/test/ui/wf/wf-unsafe-trait-obj-match.rs | 29 ++++++++ .../ui/wf/wf-unsafe-trait-obj-match.stderr | 38 ++++++++++ 59 files changed, 847 insertions(+), 105 deletions(-) create mode 100644 src/test/ui/coherence/coherence-unsafe-trait-object-impl.rs create mode 100644 src/test/ui/coherence/coherence-unsafe-trait-object-impl.stderr delete mode 100644 src/test/ui/feature-gates/feature-gate-exhaustive-patterns.nll.stderr create mode 100644 src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.rs create mode 100644 src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr rename src/test/ui/kindck/{kindck-inherited-copy-bound.stderr => kindck-inherited-copy-bound.curr.stderr} (86%) create mode 100644 src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr rename src/test/ui/object-safety/{object-safety-associated-consts.stderr => object-safety-associated-consts.curr.stderr} (88%) create mode 100644 src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr rename src/test/ui/object-safety/{object-safety-generics.stderr => object-safety-generics.curr.stderr} (89%) create mode 100644 src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr rename src/test/ui/object-safety/{object-safety-mentions-Self.stderr => object-safety-mentions-Self.curr.stderr} (83%) create mode 100644 src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr create mode 100644 src/test/ui/object-safety/object-safety-no-static.curr.stderr create mode 100644 src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr rename src/test/ui/object-safety/{object-safety-sized-2.stderr => object-safety-sized-2.curr.stderr} (89%) create mode 100644 src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr rename src/test/ui/object-safety/{object-safety-sized.stderr => object-safety-sized.curr.stderr} (90%) create mode 100644 src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr create mode 100644 src/test/ui/rfc-2027-object-safe-for-dispatch/downcast-unsafe-trait-objects.rs create mode 100644 src/test/ui/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs create mode 100644 src/test/ui/rfc-2027-object-safe-for-dispatch/static-dispatch-unsafe-object.rs create mode 100644 src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr create mode 100644 src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr create mode 100644 src/test/ui/wf/wf-convert-unsafe-trait-obj-box.rs create mode 100644 src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr create mode 100644 src/test/ui/wf/wf-convert-unsafe-trait-obj.rs create mode 100644 src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr create mode 100644 src/test/ui/wf/wf-unsafe-trait-obj-match.rs create mode 100644 src/test/ui/wf/wf-unsafe-trait-obj-match.stderr diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index f1192c7ce10a9..8f2fa3067a22f 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1146,10 +1146,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let span = cause.span(self.tcx); - diag.span_label(span, terr.to_string()); - if let Some((sp, msg)) = secondary_span { - diag.span_label(sp, msg); - } + // Ignore msg for object safe coercion + // since E0038 message will be printed + match terr { + TypeError::ObjectUnsafeCoercion(_) => {} + _ => { + diag.span_label(span, terr.to_string()); + if let Some((sp, msg)) = secondary_span { + diag.span_label(sp, msg); + } + } + }; if let Some((expected, found)) = expected_found { match (terr, is_simple_error, expected == found) { @@ -1169,6 +1176,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &sort_string(values.found), ); } + (TypeError::ObjectUnsafeCoercion(_), ..) => { + diag.note_unsuccessfull_coercion(found, expected); + } (_, false, _) => { if let Some(exp_found) = exp_found { self.suggest_as_ref_where_appropriate(span, &exp_found, diag); @@ -1267,6 +1277,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let span = trace.cause.span(self.tcx); let failure_code = trace.cause.as_failure_code(terr); let mut diag = match failure_code { + FailureCode::Error0038(did) => { + let violations = self.tcx.object_safety_violations(did); + self.tcx.report_object_safety_error(span, did, violations) + } FailureCode::Error0317(failure_str) => { struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str) } @@ -1628,6 +1642,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } enum FailureCode { + Error0038(DefId), Error0317(&'static str), Error0580(&'static str), Error0308(&'static str), @@ -1666,6 +1681,7 @@ impl<'tcx> ObligationCause<'tcx> { TypeError::IntrinsicCast => { Error0308("cannot coerce intrinsics to function pointers") } + TypeError::ObjectUnsafeCoercion(did) => Error0038(did.clone()), _ => Error0308("mismatched types"), }, } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 9eb91569ed5c4..aa376699c3855 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -790,15 +790,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty::Predicate::ObjectSafe(trait_def_id) => { let violations = self.tcx.object_safety_violations(trait_def_id); - if let Some(err) = self.tcx.report_object_safety_error( + self.tcx.report_object_safety_error( span, trait_def_id, violations, - ) { - err - } else { - return; - } + ) } ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { @@ -934,11 +930,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { TraitNotObjectSafe(did) => { let violations = self.tcx.object_safety_violations(did); - if let Some(err) = self.tcx.report_object_safety_error(span, did, violations) { - err - } else { - return; - } + self.tcx.report_object_safety_error(span, did, violations) } // already reported in the query @@ -1493,11 +1485,7 @@ impl<'tcx> TyCtxt<'tcx> { span: Span, trait_def_id: DefId, violations: Vec, - ) -> Option> { - if self.sess.trait_methods_not_found.borrow().contains(&span) { - // Avoid emitting error caused by non-existing method (#58734) - return None; - } + ) -> DiagnosticBuilder<'tcx> { let trait_str = self.def_path_str(trait_def_id); let span = self.sess.source_map().def_span(span); let mut err = struct_span_err!( @@ -1515,7 +1503,13 @@ impl<'tcx> TyCtxt<'tcx> { }; } } - Some(err) + + if self.sess.trait_methods_not_found.borrow().contains(&span) { + // Avoid emitting error caused by non-existing method (#58734) + err.cancel(); + } + + err } } @@ -1926,6 +1920,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.note(&format!("required for the cast to the object type `{}`", self.ty_to_string(object_ty))); } + ObligationCauseCode::Coercion { source: _, target } => { + err.note(&format!("required by cast to type `{}`", + self.ty_to_string(target))); + } ObligationCauseCode::RepeatVec => { err.note("the `Copy` trait is required because the \ repeated element will be copied"); diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index d96330bf0a9b4..eb4b114eb301c 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -188,6 +188,9 @@ pub enum ObligationCauseCode<'tcx> { /// Obligation incurred due to an object cast. ObjectCastObligation(/* Object type */ Ty<'tcx>), + /// Obligation incurred due to a coercion. + Coercion { source: Ty<'tcx>, target: Ty<'tcx> }, + // Various cases where expressions must be sized/copy/etc: /// L = X implies that L is Sized AssignmentLhsSized, diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 44d611ace77d0..d8a27f1e04051 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2246,7 +2246,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } if let Some(principal) = data.principal() { - principal.with_self_ty(self.tcx(), self_ty) + if !self.infcx.tcx.features().object_safe_for_dispatch { + principal.with_self_ty(self.tcx(), self_ty) + } else if self.tcx().is_object_safe(principal.def_id()) { + principal.with_self_ty(self.tcx(), self_ty) + } else { + return; + } } else { // Only auto-trait bounds exist. return; diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index dab62a6bcb5b1..9729368edfee5 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -481,6 +481,10 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { .and_then(|r| Some(super::ObjectTypeBound(ty, r))) ), super::ObjectCastObligation(ty) => tcx.lift(&ty).map(super::ObjectCastObligation), + super::Coercion { source, target } => Some(super::Coercion { + source: tcx.lift(&source)?, + target: tcx.lift(&target)?, + }), super::AssignmentLhsSized => Some(super::AssignmentLhsSized), super::TupleInitializerSized => Some(super::TupleInitializerSized), super::StructInitializerSized => Some(super::StructInitializerSized), diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 5851a48a8d377..882f330e6c339 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -45,7 +45,7 @@ pub enum TypeError<'tcx> { ProjectionMismatched(ExpectedFound), ProjectionBoundsLength(ExpectedFound), ExistentialMismatch(ExpectedFound<&'tcx ty::List>>), - + ObjectUnsafeCoercion(DefId), ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>), IntrinsicCast, @@ -179,6 +179,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { IntrinsicCast => { write!(f, "cannot coerce intrinsics to function pointers") } + ObjectUnsafeCoercion(_) => write!(f, "coercion to object-unsafe trait object"), } } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 8945e1a1debdb..3a5b8b5774121 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -749,6 +749,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch), ConstMismatch(ref x) => return tcx.lift(x).map(ConstMismatch), IntrinsicCast => IntrinsicCast, + ObjectUnsafeCoercion(ref x) => return tcx.lift(x).map(ObjectUnsafeCoercion), }) } } @@ -1356,6 +1357,7 @@ EnumTypeFoldableImpl! { (ty::error::TypeError::ExistentialMismatch)(x), (ty::error::TypeError::ConstMismatch)(x), (ty::error::TypeError::IntrinsicCast), + (ty::error::TypeError::ObjectUnsafeCoercion)(x), } } diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index ecb075e30b14d..b50e819c956e0 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -380,16 +380,21 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // obligations that don't refer to Self and // checking those - let cause = self.cause(traits::MiscObligation); - let component_traits = - data.auto_traits().chain(data.principal_def_id()); - self.out.extend( - component_traits.map(|did| traits::Obligation::new( - cause.clone(), - param_env, - ty::Predicate::ObjectSafe(did) - )) - ); + let defer_to_coercion = + self.infcx.tcx.features().object_safe_for_dispatch; + + if !defer_to_coercion { + let cause = self.cause(traits::MiscObligation); + let component_traits = + data.auto_traits().chain(data.principal_def_id()); + self.out.extend( + component_traits.map(|did| traits::Obligation::new( + cause.clone(), + param_env, + ty::Predicate::ObjectSafe(did) + )) + ); + } } // Inference variables are the complicated case, since we don't diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index fd74d8673da4d..1781f2e165033 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -152,6 +152,32 @@ impl Diagnostic { self.note_expected_found_extra(label, expected, found, &"", &"") } + pub fn note_unsuccessfull_coercion(&mut self, + expected: DiagnosticStyledString, + found: DiagnosticStyledString) + -> &mut Self + { + let mut msg: Vec<_> = + vec![(format!("required when trying to coerce from type `"), + Style::NoStyle)]; + msg.extend(expected.0.iter() + .map(|x| match *x { + StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), + StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), + })); + msg.push((format!("` to type '"), Style::NoStyle)); + msg.extend(found.0.iter() + .map(|x| match *x { + StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), + StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), + })); + msg.push((format!("`"), Style::NoStyle)); + + // For now, just attach these as notes + self.highlighted_note(msg); + self + } + pub fn note_expected_found_extra(&mut self, label: &dyn fmt::Display, expected: DiagnosticStyledString, diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index cc60bf89c7eca..40642dd14b8f7 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -209,6 +209,11 @@ impl<'a> DiagnosticBuilder<'a> { found_extra: &dyn fmt::Display, ) -> &mut Self); + forward!(pub fn note_unsuccessfull_coercion(&mut self, + expected: DiagnosticStyledString, + found: DiagnosticStyledString, + ) -> &mut Self); + forward!(pub fn note(&mut self, msg: &str) -> &mut Self); forward!(pub fn span_note>(&mut self, sp: S, diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index b8e2700803a5d..2ee5ecfbcdc25 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1275,8 +1275,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { span, item.trait_ref().def_id(), object_safety_violations - ) - .map(|mut err| err.emit()); + ).emit(); return tcx.types.err; } } diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index dfeb5fb958cd8..9cbde276ae97c 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -428,21 +428,36 @@ impl<'a, 'tcx> CastCheck<'tcx> { self.report_cast_to_unsized_type(fcx); } else if self.expr_ty.references_error() || self.cast_ty.references_error() { // No sense in giving duplicate error messages - } else if self.try_coercion_cast(fcx) { - self.trivial_cast_lint(fcx); - debug!(" -> CoercionCast"); - fcx.tables.borrow_mut().set_coercion_cast(self.expr.hir_id.local_id); - } else { - match self.do_check(fcx) { - Ok(k) => { - debug!(" -> {:?}", k); + match self.try_coercion_cast(fcx) { + Ok(()) => { + self.trivial_cast_lint(fcx); + debug!(" -> CoercionCast"); + fcx.tables.borrow_mut() + .set_coercion_cast(self.expr.hir_id.local_id); + } + Err(ty::error::TypeError::ObjectUnsafeCoercion(did)) => { + self.report_object_unsafe_cast(&fcx, did); + } + Err(_) => { + match self.do_check(fcx) { + Ok(k) => { + debug!(" -> {:?}", k); + } + Err(e) => self.report_cast_error(fcx, e), + }; } - Err(e) => self.report_cast_error(fcx, e), }; } } + fn report_object_unsafe_cast(&self, fcx: &FnCtxt<'a, 'tcx>, did: DefId) { + let violations = fcx.tcx.object_safety_violations(did); + let mut err = fcx.tcx.report_object_safety_error(self.cast_span, did, violations); + err.note(&format!("required by cast to type '{}'", fcx.ty_to_string(self.cast_ty))); + err.emit(); + } + /// Checks a cast, and report an error if one exists. In some cases, this /// can return Ok and create type errors in the fcx rather than returning /// directly. coercion-cast is handled in check instead of here. @@ -646,8 +661,14 @@ impl<'a, 'tcx> CastCheck<'tcx> { } } - fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> bool { - fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No).is_ok() + fn try_coercion_cast( + &self, + fcx: &FnCtxt<'a, 'tcx>, + ) -> Result<(), ty::error::TypeError<'_>> { + match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No) { + Ok(_) => Ok(()), + Err(err) => Err(err), + } } } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 3a89cddda2362..5c4c66bb64ed7 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -61,10 +61,11 @@ use rustc::traits::{self, ObligationCause, ObligationCauseCode}; use rustc::ty::adjustment::{ Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast }; -use rustc::ty::{self, TypeAndMut, Ty, subst::SubstsRef}; +use rustc::ty::{self, TypeAndMut, Ty}; use rustc::ty::fold::TypeFoldable; use rustc::ty::error::TypeError; use rustc::ty::relate::RelateResult; +use rustc::ty::subst::SubstsRef; use smallvec::{smallvec, SmallVec}; use std::ops::Deref; use syntax::feature_gate; @@ -196,9 +197,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // a "spurious" type variable, and we don't want to have that // type variable in memory if the coercion fails. let unsize = self.commit_if_ok(|_| self.coerce_unsized(a, b)); - if unsize.is_ok() { - debug!("coerce: unsize successful"); - return unsize; + match unsize { + Ok(_) => { + debug!("coerce: unsize successful"); + return unsize; + } + Err(TypeError::ObjectUnsafeCoercion(did)) => { + debug!("coerce: unsize not object safe"); + return Err(TypeError::ObjectUnsafeCoercion(did)); + } + Err(_) => {} } debug!("coerce: unsize failed"); @@ -539,7 +547,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let mut selcx = traits::SelectionContext::new(self); // Create an obligation for `Source: CoerceUnsized`. - let cause = ObligationCause::misc(self.cause.span, self.body_id); + let cause = ObligationCause::new( + self.cause.span, + self.body_id, + ObligationCauseCode::Coercion { source, target }, + ); // Use a FIFO queue for this custom fulfillment procedure. // @@ -566,14 +578,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let obligation = queue.remove(0); debug!("coerce_unsized resolve step: {:?}", obligation); let trait_ref = match obligation.predicate { - ty::Predicate::Trait(ref t) if traits.contains(&t.def_id()) => { - if unsize_did == t.def_id() { - if let ty::Tuple(..) = &t.skip_binder().input_types().nth(1).unwrap().kind { + ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => { + if unsize_did == tr.def_id() { + let sty = &tr.skip_binder().input_types().nth(1).unwrap().kind; + if let ty::Tuple(..) = sty { debug!("coerce_unsized: found unsized tuple coercion"); has_unsized_tuple_coercion = true; } } - t.clone() + tr.clone() } _ => { coercion.obligations.push(obligation); diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index a44c475e0f8a9..8adf4bb94a898 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -183,8 +183,11 @@ fn check_impl_overlap<'tcx>(tcx: TyCtxt<'tcx>, hir_id: HirId) { for component_def_id in component_def_ids { if !tcx.is_object_safe(component_def_id) { - // This is an error, but it will be reported by wfcheck. Ignore it here. + // Without the 'object_safe_for_dispatch' feature this is an error + // which will be reported by wfcheck. Ignore it here. // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`. + // With the feature enabled, the trait is not implemented automatically, + // so this is valid. } else { let mut supertrait_def_ids = traits::supertrait_def_ids(tcx, component_def_id); diff --git a/src/libsyntax/feature_gate/active.rs b/src/libsyntax/feature_gate/active.rs index 94f0995566f52..1386eac48dae2 100644 --- a/src/libsyntax/feature_gate/active.rs +++ b/src/libsyntax/feature_gate/active.rs @@ -528,6 +528,9 @@ declare_features! ( /// Enable accurate caller location reporting during panic (RFC 2091). (active, track_caller, "1.40.0", Some(47809), None), + /// Non-object safe trait objects safe to use but cannot be created in safe rust + (active, object_safe_for_dispatch, "1.40.0", Some(43561), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index c37efde9923a7..b80c5f83830f4 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -459,6 +459,7 @@ symbols! { no_std, not, note, + object_safe_for_dispatch, Ok, omit_gdb_pretty_printer_section, on, diff --git a/src/test/ui/coherence/coherence-unsafe-trait-object-impl.rs b/src/test/ui/coherence/coherence-unsafe-trait-object-impl.rs new file mode 100644 index 0000000000000..9859a226efd00 --- /dev/null +++ b/src/test/ui/coherence/coherence-unsafe-trait-object-impl.rs @@ -0,0 +1,18 @@ +// Check that unsafe trait object do not implement themselves +// automatically + +#![feature(object_safe_for_dispatch)] + +trait Trait: Sized { + fn call(&self); +} + +fn takes_t(s: S) { + s.call(); +} + +fn takes_t_obj(t: &dyn Trait) { + takes_t(t); //~ ERROR E0277 +} + +fn main() {} diff --git a/src/test/ui/coherence/coherence-unsafe-trait-object-impl.stderr b/src/test/ui/coherence/coherence-unsafe-trait-object-impl.stderr new file mode 100644 index 0000000000000..b5a86acfb978f --- /dev/null +++ b/src/test/ui/coherence/coherence-unsafe-trait-object-impl.stderr @@ -0,0 +1,12 @@ +error[E0277]: the trait bound `&dyn Trait: Trait` is not satisfied + --> $DIR/coherence-unsafe-trait-object-impl.rs:15:13 + | +LL | fn takes_t(s: S) { + | ------- ----- required by this bound in `takes_t` +... +LL | takes_t(t); + | ^ the trait `Trait` is not implemented for `&dyn Trait` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.nll.stderr b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.nll.stderr deleted file mode 100644 index d77fbc1e8239d..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.nll.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0005]: refutable pattern in local binding: `Err(_)` not covered - --> $DIR/feature-gate-exhaustive-patterns.rs:7:9 - | -LL | let Ok(_x) = foo(); - | ^^^^^^ pattern `Err(_)` not covered - | - = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant - = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | if let Ok(_x) = foo() { /* */ } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0005`. diff --git a/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.rs b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.rs new file mode 100644 index 0000000000000..8945360b7be6d --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.rs @@ -0,0 +1,41 @@ +// Test that the use of the non object-safe trait objects +// are gated by `object_safe_for_dispatch` feature gate. + +trait NonObjectSafe1: Sized {} + +trait NonObjectSafe2 { + fn static_fn() {} +} + +trait NonObjectSafe3 { + fn foo(&self); +} + +trait NonObjectSafe4 { + fn foo(&self, &Self); +} + +fn takes_non_object_safe_ref(obj: &dyn NonObjectSafe1) { + //~^ ERROR E0038 +} + +fn return_non_object_safe_ref() -> &'static dyn NonObjectSafe2 { + //~^ ERROR E0038 + loop {} +} + +fn takes_non_object_safe_box(obj: Box) { + //~^ ERROR E0038 +} + +fn return_non_object_safe_rc() -> std::rc::Rc { + //~^ ERROR E0038 + loop {} +} + +trait Trait {} + +impl Trait for dyn NonObjectSafe1 {} +//~^ ERROR E0038 + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr new file mode 100644 index 0000000000000..54e64e2fc1bd4 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr @@ -0,0 +1,46 @@ +error[E0038]: the trait `NonObjectSafe1` cannot be made into an object + --> $DIR/feature-gate-object_safe_for_dispatch.rs:18:1 + | +LL | fn takes_non_object_safe_ref(obj: &dyn NonObjectSafe1) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe1` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + +error[E0038]: the trait `NonObjectSafe2` cannot be made into an object + --> $DIR/feature-gate-object_safe_for_dispatch.rs:22:1 + | +LL | fn static_fn() {} + | --------- associated function `static_fn` has no `self` parameter +... +LL | fn return_non_object_safe_ref() -> &'static dyn NonObjectSafe2 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe2` cannot be made into an object + +error[E0038]: the trait `NonObjectSafe3` cannot be made into an object + --> $DIR/feature-gate-object_safe_for_dispatch.rs:27:1 + | +LL | fn foo(&self); + | --- method `foo` has generic type parameters +... +LL | fn takes_non_object_safe_box(obj: Box) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe3` cannot be made into an object + +error[E0038]: the trait `NonObjectSafe4` cannot be made into an object + --> $DIR/feature-gate-object_safe_for_dispatch.rs:31:1 + | +LL | fn foo(&self, &Self); + | --- method `foo` references the `Self` type in its parameters or return type +... +LL | fn return_non_object_safe_rc() -> std::rc::Rc { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe4` cannot be made into an object + +error[E0038]: the trait `NonObjectSafe1` cannot be made into an object + --> $DIR/feature-gate-object_safe_for_dispatch.rs:38:6 + | +LL | impl Trait for dyn NonObjectSafe1 {} + | ^^^^^ the trait `NonObjectSafe1` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/issues/issue-19538.stderr b/src/test/ui/issues/issue-19538.stderr index 5415a45f7d621..83c03b514ddcc 100644 --- a/src/test/ui/issues/issue-19538.stderr +++ b/src/test/ui/issues/issue-19538.stderr @@ -17,6 +17,7 @@ LL | let test: &mut dyn Bar = &mut thing; | ^^^^^^^^^^ the trait `Bar` cannot be made into an object | = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&mut dyn Bar>` for `&mut Thing` + = note: required by cast to type `&mut dyn Bar` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-20692.stderr b/src/test/ui/issues/issue-20692.stderr index 66309394a426d..06c83f65be26c 100644 --- a/src/test/ui/issues/issue-20692.stderr +++ b/src/test/ui/issues/issue-20692.stderr @@ -14,6 +14,7 @@ LL | let _ = x | = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Array>` for `&T` + = note: required by cast to type `&dyn Array` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-38604.stderr b/src/test/ui/issues/issue-38604.stderr index 8ef7d346cb331..8b923a2c6b23f 100644 --- a/src/test/ui/issues/issue-38604.stderr +++ b/src/test/ui/issues/issue-38604.stderr @@ -14,6 +14,7 @@ LL | Box::new(()); | = note: the trait cannot use `Self` as a type parameter in the supertraits or where-clauses = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box<()>` + = note: required by cast to type `std::boxed::Box` error: aborting due to 2 previous errors diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.stderr b/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr similarity index 86% rename from src/test/ui/kindck/kindck-inherited-copy-bound.stderr rename to src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr index 27901d0692799..a93f4686496ac 100644 --- a/src/test/ui/kindck/kindck-inherited-copy-bound.stderr +++ b/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `std::boxed::Box<{integer}>: std::marker::Copy` is not satisfied - --> $DIR/kindck-inherited-copy-bound.rs:18:16 + --> $DIR/kindck-inherited-copy-bound.rs:21:16 | LL | fn take_param(foo: &T) { } | ---------- --- required by this bound in `take_param` @@ -10,7 +10,7 @@ LL | take_param(&x); = note: required because of the requirements on the impl of `Foo` for `std::boxed::Box<{integer}>` error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/kindck-inherited-copy-bound.rs:24:19 + --> $DIR/kindck-inherited-copy-bound.rs:28:19 | LL | let z = &x as &dyn Foo; | ^^^^^^^^ the trait `Foo` cannot be made into an object @@ -18,13 +18,14 @@ LL | let z = &x as &dyn Foo; = note: the trait cannot require that `Self : Sized` error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/kindck-inherited-copy-bound.rs:24:13 + --> $DIR/kindck-inherited-copy-bound.rs:28:13 | LL | let z = &x as &dyn Foo; | ^^ the trait `Foo` cannot be made into an object | = note: the trait cannot require that `Self : Sized` = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Foo>` for `&std::boxed::Box<{integer}>` + = note: required by cast to type `&dyn Foo` error: aborting due to 3 previous errors diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr b/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr new file mode 100644 index 0000000000000..7c67c5f9e9596 --- /dev/null +++ b/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `std::boxed::Box<{integer}>: std::marker::Copy` is not satisfied + --> $DIR/kindck-inherited-copy-bound.rs:21:16 + | +LL | fn take_param(foo: &T) { } + | ---------- --- required by this bound in `take_param` +... +LL | take_param(&x); + | ^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box<{integer}>` + | + = note: required because of the requirements on the impl of `Foo` for `std::boxed::Box<{integer}>` + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/kindck-inherited-copy-bound.rs:28:13 + | +LL | let z = &x as &dyn Foo; + | ^^ the trait `Foo` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Foo>` for `&std::boxed::Box` + = note: required by cast to type `&dyn Foo` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0038, E0277. +For more information about an error, try `rustc --explain E0038`. diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.rs b/src/test/ui/kindck/kindck-inherited-copy-bound.rs index 61e72908248df..aad693e5b1937 100644 --- a/src/test/ui/kindck/kindck-inherited-copy-bound.rs +++ b/src/test/ui/kindck/kindck-inherited-copy-bound.rs @@ -1,5 +1,8 @@ // Test that Copy bounds inherited by trait are checked. +// +// revisions: curr object_safe_for_dispatch +#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] #![feature(box_syntax)] use std::any::Any; @@ -15,15 +18,17 @@ fn take_param(foo: &T) { } fn a() { let x: Box<_> = box 3; - take_param(&x); //~ ERROR E0277 + take_param(&x); //[curr]~ ERROR E0277 + //[object_safe_for_dispatch]~^ ERROR E0277 } fn b() { let x: Box<_> = box 3; let y = &x; let z = &x as &dyn Foo; - //~^ ERROR E0038 - //~| ERROR E0038 + //[curr]~^ ERROR E0038 + //[curr]~| ERROR E0038 + //[object_safe_for_dispatch]~^^^ ERROR E0038 } fn main() { } diff --git a/src/test/ui/object-safety/object-safety-associated-consts.stderr b/src/test/ui/object-safety/object-safety-associated-consts.curr.stderr similarity index 88% rename from src/test/ui/object-safety/object-safety-associated-consts.stderr rename to src/test/ui/object-safety/object-safety-associated-consts.curr.stderr index 7d5aa00356e0b..67ef7a62f1052 100644 --- a/src/test/ui/object-safety/object-safety-associated-consts.stderr +++ b/src/test/ui/object-safety/object-safety-associated-consts.curr.stderr @@ -1,5 +1,5 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-associated-consts.rs:9:1 + --> $DIR/object-safety-associated-consts.rs:12:1 | LL | const X: usize; | - the trait cannot contain associated consts like `X` diff --git a/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr new file mode 100644 index 0000000000000..20993a680ba48 --- /dev/null +++ b/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr @@ -0,0 +1,15 @@ +error[E0038]: the trait `Bar` cannot be made into an object + --> $DIR/object-safety-associated-consts.rs:14:5 + | +LL | const X: usize; + | - the trait cannot contain associated consts like `X` +... +LL | t + | ^ the trait `Bar` cannot be made into an object + | + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required by cast to type `&dyn Bar` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/object-safety/object-safety-associated-consts.rs b/src/test/ui/object-safety/object-safety-associated-consts.rs index 5900019ea915a..e1a772e5ab2f3 100644 --- a/src/test/ui/object-safety/object-safety-associated-consts.rs +++ b/src/test/ui/object-safety/object-safety-associated-consts.rs @@ -1,14 +1,18 @@ // Check that we correctly prevent users from making trait objects // from traits with associated consts. +// +// revisions: curr object_safe_for_dispatch +#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] trait Bar { const X: usize; } fn make_bar(t: &T) -> &dyn Bar { - //~^ ERROR E0038 + //[curr]~^ ERROR E0038 t + //[object_safe_for_dispatch]~^ ERROR E0038 } fn main() { diff --git a/src/test/ui/object-safety/object-safety-generics.stderr b/src/test/ui/object-safety/object-safety-generics.curr.stderr similarity index 89% rename from src/test/ui/object-safety/object-safety-generics.stderr rename to src/test/ui/object-safety/object-safety-generics.curr.stderr index b25e0052e4163..8ae9236a5c322 100644 --- a/src/test/ui/object-safety/object-safety-generics.stderr +++ b/src/test/ui/object-safety/object-safety-generics.curr.stderr @@ -1,5 +1,5 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-generics.rs:14:1 + --> $DIR/object-safety-generics.rs:18:1 | LL | fn bar(&self, t: T); | --- method `bar` has generic type parameters @@ -8,7 +8,7 @@ LL | fn make_bar(t: &T) -> &dyn Bar { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-generics.rs:19:1 + --> $DIR/object-safety-generics.rs:24:1 | LL | fn bar(&self, t: T); | --- method `bar` has generic type parameters diff --git a/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr new file mode 100644 index 0000000000000..d3d8d36888836 --- /dev/null +++ b/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr @@ -0,0 +1,27 @@ +error[E0038]: the trait `Bar` cannot be made into an object + --> $DIR/object-safety-generics.rs:20:5 + | +LL | fn bar(&self, t: T); + | --- method `bar` has generic type parameters +... +LL | t + | ^ the trait `Bar` cannot be made into an object + | + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required by cast to type `&dyn Bar` + +error[E0038]: the trait `Bar` cannot be made into an object + --> $DIR/object-safety-generics.rs:26:5 + | +LL | fn bar(&self, t: T); + | --- method `bar` has generic type parameters +... +LL | t as &dyn Bar + | ^ the trait `Bar` cannot be made into an object + | + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required by cast to type `&dyn Bar` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/object-safety/object-safety-generics.rs b/src/test/ui/object-safety/object-safety-generics.rs index d63ea28c8f227..63dcd169925e4 100644 --- a/src/test/ui/object-safety/object-safety-generics.rs +++ b/src/test/ui/object-safety/object-safety-generics.rs @@ -1,6 +1,10 @@ // Check that we correctly prevent users from making trait objects // from traits with generic methods, unless `where Self : Sized` is // present. +// revisions: curr object_safe_for_dispatch + +#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] + trait Bar { fn bar(&self, t: T); @@ -12,13 +16,15 @@ trait Quux { } fn make_bar(t: &T) -> &dyn Bar { - //~^ ERROR E0038 + //[curr]~^ ERROR E0038 t + //[object_safe_for_dispatch]~^ ERROR E0038 } fn make_bar_explicit(t: &T) -> &dyn Bar { - //~^ ERROR E0038 + //[curr]~^ ERROR E0038 t as &dyn Bar + //[object_safe_for_dispatch]~^ ERROR E0038 } fn make_quux(t: &T) -> &dyn Quux { diff --git a/src/test/ui/object-safety/object-safety-mentions-Self.stderr b/src/test/ui/object-safety/object-safety-mentions-Self.curr.stderr similarity index 83% rename from src/test/ui/object-safety/object-safety-mentions-Self.stderr rename to src/test/ui/object-safety/object-safety-mentions-Self.curr.stderr index 971e79cb0210f..297cd876187fe 100644 --- a/src/test/ui/object-safety/object-safety-mentions-Self.stderr +++ b/src/test/ui/object-safety/object-safety-mentions-Self.curr.stderr @@ -1,5 +1,5 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-mentions-Self.rs:17:1 + --> $DIR/object-safety-mentions-Self.rs:22:1 | LL | fn bar(&self, x: &Self); | --- method `bar` references the `Self` type in its parameters or return type @@ -8,10 +8,10 @@ LL | fn make_bar(t: &T) -> &dyn Bar { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object error[E0038]: the trait `Baz` cannot be made into an object - --> $DIR/object-safety-mentions-Self.rs:22:1 + --> $DIR/object-safety-mentions-Self.rs:28:1 | -LL | fn bar(&self) -> Self; - | --- method `bar` references the `Self` type in its parameters or return type +LL | fn baz(&self) -> Self; + | --- method `baz` references the `Self` type in its parameters or return type ... LL | fn make_baz(t: &T) -> &dyn Baz { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Baz` cannot be made into an object diff --git a/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr new file mode 100644 index 0000000000000..03b2b8da07533 --- /dev/null +++ b/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr @@ -0,0 +1,27 @@ +error[E0038]: the trait `Bar` cannot be made into an object + --> $DIR/object-safety-mentions-Self.rs:24:5 + | +LL | fn bar(&self, x: &Self); + | --- method `bar` references the `Self` type in its parameters or return type +... +LL | t + | ^ the trait `Bar` cannot be made into an object + | + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required by cast to type `&dyn Bar` + +error[E0038]: the trait `Baz` cannot be made into an object + --> $DIR/object-safety-mentions-Self.rs:30:5 + | +LL | fn baz(&self) -> Self; + | --- method `baz` references the `Self` type in its parameters or return type +... +LL | t + | ^ the trait `Baz` cannot be made into an object + | + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Baz>` for `&T` + = note: required by cast to type `&dyn Baz` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/object-safety/object-safety-mentions-Self.rs b/src/test/ui/object-safety/object-safety-mentions-Self.rs index f13ffe5362670..412d16ff3c7ce 100644 --- a/src/test/ui/object-safety/object-safety-mentions-Self.rs +++ b/src/test/ui/object-safety/object-safety-mentions-Self.rs @@ -1,27 +1,34 @@ // Check that we correctly prevent users from making trait objects // form traits that make use of `Self` in an argument or return // position, unless `where Self : Sized` is present.. +// +// revisions: curr object_safe_for_dispatch + +#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] + trait Bar { fn bar(&self, x: &Self); } trait Baz { - fn bar(&self) -> Self; + fn baz(&self) -> Self; } trait Quux { - fn get(&self, s: &Self) -> Self where Self : Sized; + fn quux(&self, s: &Self) -> Self where Self : Sized; } fn make_bar(t: &T) -> &dyn Bar { - //~^ ERROR E0038 - loop { } + //[curr]~^ ERROR E0038 + t + //[object_safe_for_dispatch]~^ ERROR E0038 } fn make_baz(t: &T) -> &dyn Baz { - //~^ ERROR E0038 + //[curr]~^ ERROR E0038 t + //[object_safe_for_dispatch]~^ ERROR E0038 } fn make_quux(t: &T) -> &dyn Quux { @@ -32,5 +39,4 @@ fn make_quux_explicit(t: &T) -> &dyn Quux { t as &dyn Quux } -fn main() { -} +fn main() {} diff --git a/src/test/ui/object-safety/object-safety-no-static.curr.stderr b/src/test/ui/object-safety/object-safety-no-static.curr.stderr new file mode 100644 index 0000000000000..1641ce577719e --- /dev/null +++ b/src/test/ui/object-safety/object-safety-no-static.curr.stderr @@ -0,0 +1,12 @@ +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/object-safety-no-static.rs:12:1 + | +LL | fn foo() {} + | --- associated function `foo` has no `self` parameter +... +LL | fn diverges() -> Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr new file mode 100644 index 0000000000000..91a9285b63ccc --- /dev/null +++ b/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr @@ -0,0 +1,15 @@ +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/object-safety-no-static.rs:22:27 + | +LL | fn foo() {} + | --- associated function `foo` has no `self` parameter +... +LL | let b: Box = Box::new(Bar); + | ^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object + | + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box` + = note: required by cast to type `std::boxed::Box` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/object-safety/object-safety-no-static.rs b/src/test/ui/object-safety/object-safety-no-static.rs index 55d31ce808769..03b6221748388 100644 --- a/src/test/ui/object-safety/object-safety-no-static.rs +++ b/src/test/ui/object-safety/object-safety-no-static.rs @@ -1,14 +1,24 @@ // Check that we correctly prevent users from making trait objects // from traits with static methods. +// +// revisions: curr object_safe_for_dispatch + +#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] trait Foo { - fn foo(); + fn foo() {} } -fn foo_implicit(b: Box) -> Box { - //~^ ERROR E0038 +fn diverges() -> Box { + //[curr]~^ ERROR E0038 loop { } } +struct Bar; + +impl Foo for Bar {} + fn main() { + let b: Box = Box::new(Bar); + //[object_safe_for_dispatch]~^ ERROR E0038 } diff --git a/src/test/ui/object-safety/object-safety-sized-2.stderr b/src/test/ui/object-safety/object-safety-sized-2.curr.stderr similarity index 89% rename from src/test/ui/object-safety/object-safety-sized-2.stderr rename to src/test/ui/object-safety/object-safety-sized-2.curr.stderr index dcaf2ff0bc294..1e1d2bf64c427 100644 --- a/src/test/ui/object-safety/object-safety-sized-2.stderr +++ b/src/test/ui/object-safety/object-safety-sized-2.curr.stderr @@ -1,5 +1,5 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-sized-2.rs:10:1 + --> $DIR/object-safety-sized-2.rs:14:1 | LL | fn make_bar(t: &T) -> &dyn Bar { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object diff --git a/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr new file mode 100644 index 0000000000000..06ecfd019c841 --- /dev/null +++ b/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr @@ -0,0 +1,13 @@ +error[E0038]: the trait `Bar` cannot be made into an object + --> $DIR/object-safety-sized-2.rs:16:5 + | +LL | t + | ^ the trait `Bar` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required by cast to type `&dyn Bar` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/object-safety/object-safety-sized-2.rs b/src/test/ui/object-safety/object-safety-sized-2.rs index 7235b22404e29..1e79b8cd917c7 100644 --- a/src/test/ui/object-safety/object-safety-sized-2.rs +++ b/src/test/ui/object-safety/object-safety-sized-2.rs @@ -1,5 +1,9 @@ // Check that we correctly prevent users from making trait objects // from traits where `Self : Sized`. +// +// revisions: curr object_safe_for_dispatch + +#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] trait Bar where Self : Sized @@ -8,8 +12,9 @@ trait Bar } fn make_bar(t: &T) -> &dyn Bar { - //~^ ERROR E0038 - loop { } + //[curr]~^ ERROR E0038 + t + //[object_safe_for_dispatch]~^ ERROR E0038 } fn main() { diff --git a/src/test/ui/object-safety/object-safety-sized.stderr b/src/test/ui/object-safety/object-safety-sized.curr.stderr similarity index 90% rename from src/test/ui/object-safety/object-safety-sized.stderr rename to src/test/ui/object-safety/object-safety-sized.curr.stderr index 98bc73e38d4cc..1a67e79e83d32 100644 --- a/src/test/ui/object-safety/object-safety-sized.stderr +++ b/src/test/ui/object-safety/object-safety-sized.curr.stderr @@ -1,5 +1,5 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/object-safety-sized.rs:8:1 + --> $DIR/object-safety-sized.rs:12:1 | LL | fn make_bar(t: &T) -> &dyn Bar { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object diff --git a/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr new file mode 100644 index 0000000000000..3d88dfc40ed38 --- /dev/null +++ b/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr @@ -0,0 +1,13 @@ +error[E0038]: the trait `Bar` cannot be made into an object + --> $DIR/object-safety-sized.rs:14:5 + | +LL | t + | ^ the trait `Bar` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required by cast to type `&dyn Bar` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/object-safety/object-safety-sized.rs b/src/test/ui/object-safety/object-safety-sized.rs index 1312bb34717ee..b424b892d3b45 100644 --- a/src/test/ui/object-safety/object-safety-sized.rs +++ b/src/test/ui/object-safety/object-safety-sized.rs @@ -1,13 +1,18 @@ // Check that we correctly prevent users from making trait objects // from traits where `Self : Sized`. +// +// revisions: curr object_safe_for_dispatch + +#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] trait Bar : Sized { fn bar(&self, t: T); } fn make_bar(t: &T) -> &dyn Bar { - //~^ ERROR E0038 + //[curr]~^ ERROR E0038 t + //[object_safe_for_dispatch]~^ ERROR E0038 } fn main() { diff --git a/src/test/ui/rfc-2027-object-safe-for-dispatch/downcast-unsafe-trait-objects.rs b/src/test/ui/rfc-2027-object-safe-for-dispatch/downcast-unsafe-trait-objects.rs new file mode 100644 index 0000000000000..fa04f4b12d5fe --- /dev/null +++ b/src/test/ui/rfc-2027-object-safe-for-dispatch/downcast-unsafe-trait-objects.rs @@ -0,0 +1,23 @@ +// Check that we if we get ahold of an object unsafe trait +// object with auto traits and lifetimes, we can downcast it +// +// check-pass + +#![feature(object_safe_for_dispatch)] + +trait Trait: Sized {} + +fn downcast_auto(t: &(dyn Trait + Send)) -> &dyn Trait { + t +} + +fn downcast_lifetime<'a, 'b, 't>(t: &'a (dyn Trait + 't)) + -> &'b (dyn Trait + 't) +where + 'a: 'b, + 't: 'a + 'b, +{ + t +} + +fn main() {} diff --git a/src/test/ui/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs b/src/test/ui/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs new file mode 100644 index 0000000000000..1dea401226569 --- /dev/null +++ b/src/test/ui/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs @@ -0,0 +1,69 @@ +// Check that we can manually implement an object +// unsafe trait for its trait object +// +// run-pass + +#![feature(object_safe_for_dispatch)] + +trait Bad { + fn stat() -> char { + 'A' + } + fn virt(&self) -> char { + 'B' + } + fn indirect(&self) -> char { + Self::stat() + } +} + +trait Good { + fn good_virt(&self) -> char { + panic!() + } + fn good_indirect(&self) -> char { + panic!() + } +} + +impl<'a> Bad for dyn Bad + 'a { + fn stat() -> char { + 'C' + } + fn virt(&self) -> char { + 'D' + } +} + +struct Struct {} + +impl Bad for Struct {} + +impl Good for Struct {} + +fn main() { + let s = Struct {}; + + let mut res = String::new(); + + // Directly call static + res.push(Struct::stat()); // "A" + res.push(::stat()); // "AC" + + let good: &dyn Good = &s; + + // These look similar enough... + let bad = unsafe { std::mem::transmute::<&dyn Good, &dyn Bad>(good) }; + + // Call virtual + res.push(s.virt()); // "ACB" + res.push(bad.virt()); // "ACBD" + + // Indirectly call static + res.push(s.indirect()); // "ACBDA" + res.push(bad.indirect()); // "ACBDAC" + + if &res != "ACBDAC" { + panic!(); + } +} diff --git a/src/test/ui/rfc-2027-object-safe-for-dispatch/static-dispatch-unsafe-object.rs b/src/test/ui/rfc-2027-object-safe-for-dispatch/static-dispatch-unsafe-object.rs new file mode 100644 index 0000000000000..df97d2c13278e --- /dev/null +++ b/src/test/ui/rfc-2027-object-safe-for-dispatch/static-dispatch-unsafe-object.rs @@ -0,0 +1,37 @@ +// Check that we can statically dispatch methods for object +// unsafe trait objects, directly and indirectly +// +// check-pass + +#![feature(object_safe_for_dispatch)] + +trait Statics { + fn plain() {} + fn generic() {} +} + +trait Trait: Sized {} + +impl<'a> Statics for dyn Trait + 'a {} + +fn static_poly() { + T::plain(); + T::generic::(); +} + +fn inferred_poly(t: &T) { + static_poly::(); + T::plain(); + T::generic::(); +} + +fn call(t: &dyn Trait) { + static_poly::(); + inferred_poly(t); +} + +fn main() { + static_poly::(); + ::plain(); + ::generic::() +} diff --git a/src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr b/src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr new file mode 100644 index 0000000000000..cdffc1d86edfb --- /dev/null +++ b/src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr @@ -0,0 +1,24 @@ +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/arbitrary-self-types-not-object-safe.rs:34:32 + | +LL | fn foo(self: &Rc) -> usize; + | --- method `foo`'s `self` parameter cannot be dispatched on +... +LL | let x = Rc::new(5usize) as Rc; + | ^^^^^^^^^^^ the trait `Foo` cannot be made into an object + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/arbitrary-self-types-not-object-safe.rs:34:13 + | +LL | fn foo(self: &Rc) -> usize; + | --- method `foo`'s `self` parameter cannot be dispatched on +... +LL | let x = Rc::new(5usize) as Rc; + | ^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object + | + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::rc::Rc` + = note: required by cast to type `std::rc::Rc` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr b/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr new file mode 100644 index 0000000000000..725632a12126e --- /dev/null +++ b/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr @@ -0,0 +1,15 @@ +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/arbitrary-self-types-not-object-safe.rs:34:13 + | +LL | fn foo(self: &Rc) -> usize; + | --- method `foo`'s `self` parameter cannot be dispatched on +... +LL | let x = Rc::new(5usize) as Rc; + | ^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object + | + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::rc::Rc` + = note: required by cast to type `std::rc::Rc` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/self/arbitrary-self-types-not-object-safe.rs b/src/test/ui/self/arbitrary-self-types-not-object-safe.rs index 7443d888c9ec8..2eeabad28db02 100644 --- a/src/test/ui/self/arbitrary-self-types-not-object-safe.rs +++ b/src/test/ui/self/arbitrary-self-types-not-object-safe.rs @@ -1,3 +1,6 @@ +// revisions: curr object_safe_for_dispatch + +#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] #![feature(arbitrary_self_types)] use std::rc::Rc; @@ -29,8 +32,9 @@ impl Bar for usize { fn make_foo() { let x = Rc::new(5usize) as Rc; - //~^ ERROR E0038 - //~| ERROR E0038 + //[curr]~^ ERROR E0038 + //[curr]~| ERROR E0038 + //[object_safe_for_dispatch]~^^^ ERROR E0038 } fn make_bar() { diff --git a/src/test/ui/traits/trait-object-safety.stderr b/src/test/ui/traits/trait-object-safety.stderr index 3ac1e96b30c95..028e9eedd641a 100644 --- a/src/test/ui/traits/trait-object-safety.stderr +++ b/src/test/ui/traits/trait-object-safety.stderr @@ -8,6 +8,7 @@ LL | let _: &dyn Tr = &St; | ^^^ the trait `Tr` cannot be made into an object | = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Tr>` for `&St` + = note: required by cast to type `&dyn Tr` error[E0038]: the trait `Tr` cannot be made into an object --> $DIR/trait-object-safety.rs:15:12 diff --git a/src/test/ui/traits/trait-test-2.stderr b/src/test/ui/traits/trait-test-2.stderr index 83c2c06527493..9b750d382ec96 100644 --- a/src/test/ui/traits/trait-test-2.stderr +++ b/src/test/ui/traits/trait-test-2.stderr @@ -33,6 +33,7 @@ LL | (box 10 as Box).dup(); | ^^^^^^ the trait `bar` cannot be made into an object | = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box<{integer}>` + = note: required by cast to type `std::boxed::Box` error: aborting due to 4 previous errors diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.rs b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.rs new file mode 100644 index 0000000000000..ffdb49a3be5c7 --- /dev/null +++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.rs @@ -0,0 +1,18 @@ +// Check that we do not allow casts or coercions +// to object unsafe trait objects inside a Box + +#![feature(object_safe_for_dispatch)] + +trait Trait: Sized {} + +struct S; + +impl Trait for S {} + +fn takes_box(t: Box) {} + +fn main() { + Box::new(S) as Box; //~ ERROR E0038 + let t_box: Box = Box::new(S); //~ ERROR E0038 + takes_box(Box::new(S)); //~ ERROR E0038 +} diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr new file mode 100644 index 0000000000000..0b63aef2bce10 --- /dev/null +++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr @@ -0,0 +1,33 @@ +error[E0038]: the trait `Trait` cannot be made into an object + --> $DIR/wf-convert-unsafe-trait-obj-box.rs:16:33 + | +LL | let t_box: Box = Box::new(S); + | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box` + = note: required by cast to type `std::boxed::Box` + +error[E0038]: the trait `Trait` cannot be made into an object + --> $DIR/wf-convert-unsafe-trait-obj-box.rs:17:15 + | +LL | takes_box(Box::new(S)); + | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box` + = note: required by cast to type `std::boxed::Box<(dyn Trait + 'static)>` + +error[E0038]: the trait `Trait` cannot be made into an object + --> $DIR/wf-convert-unsafe-trait-obj-box.rs:15:5 + | +LL | Box::new(S) as Box; + | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box` + = note: required by cast to type `std::boxed::Box` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj.rs b/src/test/ui/wf/wf-convert-unsafe-trait-obj.rs new file mode 100644 index 0000000000000..143b854ed6b2d --- /dev/null +++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj.rs @@ -0,0 +1,18 @@ +// Check that we do not allow casts or coercions +// to object unsafe trait objects by ref + +#![feature(object_safe_for_dispatch)] + +trait Trait: Sized {} + +struct S; + +impl Trait for S {} + +fn takes_trait(t: &dyn Trait) {} + +fn main() { + &S as &dyn Trait; //~ ERROR E0038 + let t: &dyn Trait = &S; //~ ERROR E0038 + takes_trait(&S); //~ ERROR E0038 +} diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr b/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr new file mode 100644 index 0000000000000..7aeefd731fb28 --- /dev/null +++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr @@ -0,0 +1,33 @@ +error[E0038]: the trait `Trait` cannot be made into an object + --> $DIR/wf-convert-unsafe-trait-obj.rs:16:25 + | +LL | let t: &dyn Trait = &S; + | ^^ the trait `Trait` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` + = note: required by cast to type `&dyn Trait` + +error[E0038]: the trait `Trait` cannot be made into an object + --> $DIR/wf-convert-unsafe-trait-obj.rs:17:17 + | +LL | takes_trait(&S); + | ^^ the trait `Trait` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` + = note: required by cast to type `&dyn Trait` + +error[E0038]: the trait `Trait` cannot be made into an object + --> $DIR/wf-convert-unsafe-trait-obj.rs:15:5 + | +LL | &S as &dyn Trait; + | ^^ the trait `Trait` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` + = note: required by cast to type `&dyn Trait` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/wf/wf-unsafe-trait-obj-match.rs b/src/test/ui/wf/wf-unsafe-trait-obj-match.rs new file mode 100644 index 0000000000000..c8731a8ecafa4 --- /dev/null +++ b/src/test/ui/wf/wf-unsafe-trait-obj-match.rs @@ -0,0 +1,29 @@ +// Check that we do not allow coercions to object +// unsafe trait objects in match arms + +#![feature(object_safe_for_dispatch)] + +trait Trait: Sized {} + +struct S; + +impl Trait for S {} + +struct R; + +impl Trait for R {} + +fn opt() -> Option<()> { + Some(()) +} + +fn main() { + match opt() { + Some(()) => &S, + None => &R, //~ ERROR E0308 + } + let t: &dyn Trait = match opt() { //~ ERROR E0038 + Some(()) => &S, //~ ERROR E0038 + None => &R, + }; +} diff --git a/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr b/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr new file mode 100644 index 0000000000000..185b1e6c36b55 --- /dev/null +++ b/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr @@ -0,0 +1,38 @@ +error[E0308]: match arms have incompatible types + --> $DIR/wf-unsafe-trait-obj-match.rs:23:17 + | +LL | / match opt() { +LL | | Some(()) => &S, + | | -- this is found to be of type `&S` +LL | | None => &R, + | | ^^ expected struct `S`, found struct `R` +LL | | } + | |_____- `match` arms have incompatible types + | + = note: expected type `&S` + found type `&R` + +error[E0038]: the trait `Trait` cannot be made into an object + --> $DIR/wf-unsafe-trait-obj-match.rs:26:21 + | +LL | Some(()) => &S, + | ^^ the trait `Trait` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` + = note: required by cast to type `&dyn Trait` + +error[E0038]: the trait `Trait` cannot be made into an object + --> $DIR/wf-unsafe-trait-obj-match.rs:25:25 + | +LL | let t: &dyn Trait = match opt() { + | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&R` + = note: required by cast to type `&dyn Trait` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0038, E0308. +For more information about an error, try `rustc --explain E0038`.