diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 51ee56080a2ce..be04fa7436b9a 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -337,9 +337,6 @@ declare_features! ( /// Allows `#[track_caller]` to be used which provides /// accurate caller location reporting during panic (RFC 2091). (accepted, track_caller, "1.46.0", Some(47809)), - /// Allows dyn upcasting trait objects via supertraits. - /// Dyn upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`. - (accepted, trait_upcasting, "1.76.0", Some(65991)), /// Allows #[repr(transparent)] on univariant enums (RFC 2645). (accepted, transparent_enums, "1.42.0", Some(60405)), /// Allows indexing tuples. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 1ad75a692c7cd..eadb19f6fc36c 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -580,6 +580,9 @@ declare_features! ( (unstable, thread_local, "1.0.0", Some(29594)), /// Allows defining `trait X = A + B;` alias items. (unstable, trait_alias, "1.24.0", Some(41517)), + /// Allows dyn upcasting trait objects via supertraits. + /// Dyn upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`. + (unstable, trait_upcasting, "1.56.0", Some(65991)), /// Allows for transmuting between arrays with sizes that contain generic consts. (unstable, transmute_generic_consts, "1.70.0", Some(109929)), /// Allows #[repr(transparent)] on unions (RFC 2645). diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 61236c07135cd..f08af9edcbbfc 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -627,6 +627,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { )]; let mut has_unsized_tuple_coercion = false; + let mut has_trait_upcasting_coercion = None; // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where @@ -694,6 +695,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // these here and emit a feature error if coercion doesn't fail // due to another reason. match impl_source { + traits::ImplSource::Builtin( + BuiltinImplSource::TraitUpcasting { .. }, + _, + ) => { + has_trait_upcasting_coercion = + Some((trait_pred.self_ty(), trait_pred.trait_ref.args.type_at(1))); + } traits::ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => { has_unsized_tuple_coercion = true; } @@ -704,6 +712,21 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } } + if let Some((sub, sup)) = has_trait_upcasting_coercion + && !self.tcx().features().trait_upcasting + { + // Renders better when we erase regions, since they're not really the point here. + let (sub, sup) = self.tcx.erase_regions((sub, sup)); + let mut err = feature_err( + &self.tcx.sess.parse_sess, + sym::trait_upcasting, + self.cause.span, + format!("cannot cast `{sub}` to `{sup}`, trait upcasting coercion is experimental"), + ); + err.note(format!("required when coercing `{source}` into `{target}`")); + err.emit(); + } + if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion { feature_err( &self.tcx.sess.parse_sess, diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs index 98bafc0f2637e..4673b801dc1db 100644 --- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs +++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs @@ -5,6 +5,7 @@ use crate::{ use rustc_hir as hir; use rustc_middle::ty; +use rustc_session::lint::FutureIncompatibilityReason; use rustc_span::sym; use rustc_trait_selection::traits::supertraits; @@ -12,6 +13,9 @@ declare_lint! { /// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the /// `Deref` implementation with a `dyn SuperTrait` type as `Output`. /// + /// These implementations will become shadowed when the `trait_upcasting` feature is stabilized. + /// The `deref` functions will no longer be called implicitly, so there might be behavior change. + /// /// ### Example /// /// ```rust,compile_fail @@ -40,10 +44,15 @@ declare_lint! { /// /// ### Explanation /// - /// The implicit dyn upcasting coercion take priority over those `Deref` impls. + /// The dyn upcasting coercion feature adds new coercion rules, taking priority + /// over certain other coercion rules, which will cause some behavior change. pub DEREF_INTO_DYN_SUPERTRAIT, Warn, - "`Deref` implementation usage with a supertrait trait object for output are shadow by implicit coercion", + "`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseSemanticsChange, + reference: "issue #89460 ", + }; } declare_lint_pass!(DerefIntoDynSupertrait => [DEREF_INTO_DYN_SUPERTRAIT]); diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index a4ab5527e3fc0..066c88cc6524a 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -39,7 +39,7 @@ #![feature(min_specialization)] #![feature(never_type)] #![feature(rustc_attrs)] -#![cfg_attr(bootstrap, feature(trait_upcasting))] +#![feature(trait_upcasting)] #![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index ca6408bdf3ddb..9c0d3be0318c3 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -544,7 +544,6 @@ pub enum BuiltinSpecialModuleNameUsed { // deref_into_dyn_supertrait.rs #[derive(LintDiagnostic)] #[diag(lint_supertrait_as_deref_target)] -#[help] pub struct SupertraitAsDerefTarget<'a> { pub self_ty: Ty<'a>, pub supertrait_principal: PolyExistentialTraitRef<'a>, diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index e048268fad120..3206c6cf650e2 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -49,7 +49,7 @@ #![feature(associated_type_bounds)] #![feature(rustc_attrs)] #![feature(control_flow_enum)] -#![cfg_attr(bootstrap, feature(trait_upcasting))] +#![feature(trait_upcasting)] #![feature(trusted_step)] #![feature(try_blocks)] #![feature(try_reserve_kind)] diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 73e06b8408562..38b1046ac53e2 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -9,10 +9,13 @@ use hir::def_id::DefId; use hir::LangItem; use rustc_hir as hir; +use rustc_infer::traits::ObligationCause; use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError}; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; +use crate::traits; +use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::util; use super::BuiltinImplConditions; @@ -723,6 +726,45 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) } + /// Temporary migration for #89190 + fn need_migrate_deref_output_trait_object( + &mut self, + ty: Ty<'tcx>, + param_env: ty::ParamEnv<'tcx>, + cause: &ObligationCause<'tcx>, + ) -> Option> { + let tcx = self.tcx(); + if tcx.features().trait_upcasting { + return None; + } + + // + let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]); + + let obligation = + traits::Obligation::new(tcx, cause.clone(), param_env, ty::Binder::dummy(trait_ref)); + if !self.infcx.predicate_may_hold(&obligation) { + return None; + } + + self.infcx.probe(|_| { + let ty = traits::normalize_projection_type( + self, + param_env, + ty::AliasTy::new(tcx, tcx.lang_items().deref_target()?, trait_ref.args), + cause.clone(), + 0, + // We're *intentionally* throwing these away, + // since we don't actually use them. + &mut vec![], + ) + .ty() + .unwrap(); + + if let ty::Dynamic(data, ..) = ty.kind() { data.principal() } else { None } + }) + } + /// Searches for unsizing that might apply to `obligation`. fn assemble_candidates_for_unsizing( &mut self, @@ -780,6 +822,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let principal_a = a_data.principal().unwrap(); let target_trait_did = principal_def_id_b.unwrap(); let source_trait_ref = principal_a.with_self_ty(self.tcx(), source); + if let Some(deref_trait_ref) = self.need_migrate_deref_output_trait_object( + source, + obligation.param_env, + &obligation.cause, + ) { + if deref_trait_ref.def_id() == target_trait_did { + return; + } + } for (idx, upcast_trait_ref) in util::supertraits(self.tcx(), source_trait_ref).enumerate() diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index c531117bed5ad..ac8b6f6b56714 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -111,7 +111,7 @@ #![feature(slice_flatten)] #![feature(error_generic_member_access)] #![feature(error_in_core)] -#![cfg_attr(bootstrap, feature(trait_upcasting))] +#![feature(trait_upcasting)] #![feature(utf8_chunks)] #![feature(is_ascii_octdigit)] #![feature(get_many_mut)] diff --git a/src/doc/unstable-book/src/language-features/trait-upcasting.md b/src/doc/unstable-book/src/language-features/trait-upcasting.md new file mode 100644 index 0000000000000..3697ae38f9d81 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/trait-upcasting.md @@ -0,0 +1,27 @@ +# `trait_upcasting` + +The tracking issue for this feature is: [#65991] + +[#65991]: https://github.com/rust-lang/rust/issues/65991 + +------------------------ + +The `trait_upcasting` feature adds support for trait upcasting coercion. This allows a +trait object of type `dyn Bar` to be cast to a trait object of type `dyn Foo` +so long as `Bar: Foo`. + +```rust,edition2018 +#![feature(trait_upcasting)] +#![allow(incomplete_features)] + +trait Foo {} + +trait Bar: Foo {} + +impl Foo for i32 {} + +impl Bar for T {} + +let bar: &dyn Bar = &123; +let foo: &dyn Foo = bar; +``` diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 1eb40ab826c45..70e9c443e90ec 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -11,7 +11,7 @@ #![feature(round_ties_even)] #![feature(let_chains)] #![feature(lint_reasons)] -#![cfg_attr(bootstrap, feature(trait_upcasting))] +#![feature(trait_upcasting)] // Configure clippy and other lints #![allow( clippy::collapsible_else_if, diff --git a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs index 7d46ecd8f6ea8..648ac07c43ec9 100644 --- a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs +++ b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs @@ -1,3 +1,6 @@ +#![feature(trait_upcasting)] +#![allow(incomplete_features)] + trait Foo: PartialEq + std::fmt::Debug + Send + Sync { fn a(&self) -> i32 { 10 diff --git a/src/tools/miri/tests/pass/box-custom-alloc.rs b/src/tools/miri/tests/pass/box-custom-alloc.rs index 3d055961d15de..155e3d74ab9c1 100644 --- a/src/tools/miri/tests/pass/box-custom-alloc.rs +++ b/src/tools/miri/tests/pass/box-custom-alloc.rs @@ -1,6 +1,7 @@ //@revisions: stack tree //@[tree]compile-flags: -Zmiri-tree-borrows -#![feature(allocator_api)] +#![allow(incomplete_features)] // for trait upcasting +#![feature(allocator_api, trait_upcasting)] use std::alloc::Layout; use std::alloc::{AllocError, Allocator}; diff --git a/src/tools/miri/tests/pass/dyn-upcast.rs b/src/tools/miri/tests/pass/dyn-upcast.rs index ddaefeca3a3be..8432012a9ba52 100644 --- a/src/tools/miri/tests/pass/dyn-upcast.rs +++ b/src/tools/miri/tests/pass/dyn-upcast.rs @@ -1,3 +1,6 @@ +#![feature(trait_upcasting)] +#![allow(incomplete_features)] + fn main() { basic(); diamond(); diff --git a/tests/ui/codegen/issue-99551.rs b/tests/ui/codegen/issue-99551.rs index 9e203fba113c9..b223aff4e9492 100644 --- a/tests/ui/codegen/issue-99551.rs +++ b/tests/ui/codegen/issue-99551.rs @@ -1,4 +1,5 @@ // build-pass +#![feature(trait_upcasting)] pub trait A {} pub trait B {} diff --git a/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.rs b/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.rs index 0201c8897065c..a4eb669e32104 100644 --- a/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.rs +++ b/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.rs @@ -1,4 +1,4 @@ -#![feature(dyn_star)] +#![feature(dyn_star, trait_upcasting)] //~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes trait A: B {} diff --git a/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr b/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr index 7e2cf661369b9..1f7bfb1d5bdc5 100644 --- a/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr +++ b/tests/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr @@ -1,7 +1,7 @@ warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/no-unsize-coerce-dyn-trait.rs:1:12 | -LL | #![feature(dyn_star)] +LL | #![feature(dyn_star, trait_upcasting)] | ^^^^^^^^ | = note: see issue #102425 for more information diff --git a/tests/ui/dyn-star/upcast.rs b/tests/ui/dyn-star/upcast.rs index 7748cdda943c2..c667ac143a395 100644 --- a/tests/ui/dyn-star/upcast.rs +++ b/tests/ui/dyn-star/upcast.rs @@ -1,6 +1,6 @@ // known-bug: #104800 -#![feature(dyn_star)] +#![feature(dyn_star, trait_upcasting)] trait Foo: Bar { fn hello(&self); diff --git a/tests/ui/dyn-star/upcast.stderr b/tests/ui/dyn-star/upcast.stderr index bdf77da713a0e..adef9525bf1fa 100644 --- a/tests/ui/dyn-star/upcast.stderr +++ b/tests/ui/dyn-star/upcast.stderr @@ -1,7 +1,7 @@ warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/upcast.rs:3:12 | -LL | #![feature(dyn_star)] +LL | #![feature(dyn_star, trait_upcasting)] | ^^^^^^^^ | = note: see issue #102425 for more information diff --git a/tests/ui/feature-gates/feature-gate-trait_upcasting.rs b/tests/ui/feature-gates/feature-gate-trait_upcasting.rs new file mode 100644 index 0000000000000..e4102f1cfa75d --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-trait_upcasting.rs @@ -0,0 +1,13 @@ +trait Foo {} + +trait Bar: Foo {} + +impl Foo for () {} + +impl Bar for () {} + +fn main() { + let bar: &dyn Bar = &(); + let foo: &dyn Foo = bar; + //~^ ERROR trait upcasting coercion is experimental [E0658] +} diff --git a/tests/ui/feature-gates/feature-gate-trait_upcasting.stderr b/tests/ui/feature-gates/feature-gate-trait_upcasting.stderr new file mode 100644 index 0000000000000..ce2f3c0a808ad --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-trait_upcasting.stderr @@ -0,0 +1,13 @@ +error[E0658]: cannot cast `dyn Bar` to `dyn Foo`, trait upcasting coercion is experimental + --> $DIR/feature-gate-trait_upcasting.rs:11:25 + | +LL | let foo: &dyn Foo = bar; + | ^^^ + | + = note: see issue #65991 for more information + = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable + = note: required when coercing `&dyn Bar` into `&dyn Foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/next-solver/normalize-unsize-rhs.rs b/tests/ui/traits/next-solver/normalize-unsize-rhs.rs index 6ca82d1b872c7..08bb0cf42e805 100644 --- a/tests/ui/traits/next-solver/normalize-unsize-rhs.rs +++ b/tests/ui/traits/next-solver/normalize-unsize-rhs.rs @@ -1,5 +1,6 @@ // compile-flags: -Znext-solver // check-pass +#![feature(trait_upcasting)] trait A {} trait B: A {} diff --git a/tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs b/tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs index 2a482f7466865..8e0378e94f043 100644 --- a/tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs +++ b/tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs @@ -1,5 +1,6 @@ // check-pass // compile-flags: -Znext-solver +#![feature(trait_upcasting)] pub trait A {} pub trait B: A {} diff --git a/tests/ui/traits/next-solver/upcast-right-substs.rs b/tests/ui/traits/next-solver/upcast-right-substs.rs index 5e4d958c89591..5b4f6d4be0ca8 100644 --- a/tests/ui/traits/next-solver/upcast-right-substs.rs +++ b/tests/ui/traits/next-solver/upcast-right-substs.rs @@ -1,5 +1,6 @@ // compile-flags: -Znext-solver // check-pass +#![feature(trait_upcasting)] trait Foo: Bar + Bar {} diff --git a/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs index 927a9d6b94f8a..4a5e445d1efbe 100644 --- a/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs +++ b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.rs @@ -1,3 +1,4 @@ +#![feature(trait_upcasting)] #![feature(trait_alias)] // Although we *elaborate* `T: Alias` to `i32: B`, we should diff --git a/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr index 1a410519a4edc..99c82b88d9c38 100644 --- a/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr +++ b/tests/ui/traits/trait-upcasting/alias-where-clause-isnt-supertrait.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/alias-where-clause-isnt-supertrait.rs:26:5 + --> $DIR/alias-where-clause-isnt-supertrait.rs:27:5 | LL | fn test(x: &dyn C) -> &dyn B { | ------ expected `&dyn B` because of return type diff --git a/tests/ui/traits/trait-upcasting/basic.rs b/tests/ui/traits/trait-upcasting/basic.rs index 538cd8329cc64..570ec5160bfe9 100644 --- a/tests/ui/traits/trait-upcasting/basic.rs +++ b/tests/ui/traits/trait-upcasting/basic.rs @@ -1,5 +1,7 @@ // run-pass +#![feature(trait_upcasting)] + trait Foo: PartialEq + std::fmt::Debug + Send + Sync { fn a(&self) -> i32 { 10 diff --git a/tests/ui/traits/trait-upcasting/correct-supertrait-substitution.rs b/tests/ui/traits/trait-upcasting/correct-supertrait-substitution.rs index 4a379d9f875b8..eae5cf8d58d01 100644 --- a/tests/ui/traits/trait-upcasting/correct-supertrait-substitution.rs +++ b/tests/ui/traits/trait-upcasting/correct-supertrait-substitution.rs @@ -1,4 +1,5 @@ // run-pass +#![feature(trait_upcasting)] trait Foo: Bar + Bar {} trait Bar { diff --git a/tests/ui/traits/trait-upcasting/deref-lint-regions.stderr b/tests/ui/traits/trait-upcasting/deref-lint-regions.stderr deleted file mode 100644 index 557a4420a3dbf..0000000000000 --- a/tests/ui/traits/trait-upcasting/deref-lint-regions.stderr +++ /dev/null @@ -1,14 +0,0 @@ -warning: this `Deref` implementation is covered by an implicit supertrait coercion - --> $DIR/deref-lint-regions.rs:8:1 - | -LL | impl<'a> Deref for dyn Foo<'a> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Foo<'_>` implements `Deref>` which conflicts with supertrait `Bar<'_>` -LL | -LL | type Target = dyn Bar<'a>; - | -------------------------- target type is a supertrait of `dyn Foo<'_>` - | - = help: consider removing this implementation or replacing it with a method instead - = note: `#[warn(deref_into_dyn_supertrait)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/traits/trait-upcasting/deref-lint.stderr b/tests/ui/traits/trait-upcasting/deref-lint.stderr deleted file mode 100644 index 5a13659edf568..0000000000000 --- a/tests/ui/traits/trait-upcasting/deref-lint.stderr +++ /dev/null @@ -1,14 +0,0 @@ -warning: this `Deref` implementation is covered by an implicit supertrait coercion - --> $DIR/deref-lint.rs:9:1 - | -LL | impl<'a> Deref for dyn 'a + B { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn B` implements `Deref` which conflicts with supertrait `A` -... -LL | type Target = dyn A; - | -------------------- target type is a supertrait of `dyn B` - | - = help: consider removing this implementation or replacing it with a method instead - = note: `#[warn(deref_into_dyn_supertrait)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.rs b/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.rs index 366eae1a58a34..e4784fa41011b 100644 --- a/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.rs +++ b/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.rs @@ -15,6 +15,8 @@ impl Foo for () { } impl<'a> Deref for dyn Foo + 'a { + //~^ ERROR this `Deref` implementation is covered by an implicit supertrait coercion + //~| WARN this will change its meaning in a future release! type Target = dyn Bar + 'a; fn deref(&self) -> &Self::Target { @@ -30,5 +32,4 @@ fn main() { let x: &dyn Foo = &(); let y = take_dyn(x); let z: u32 = y; - //~^ ERROR mismatched types } diff --git a/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.stderr b/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.stderr index 193d09e350111..fa93e28c73bce 100644 --- a/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.stderr +++ b/tests/ui/traits/trait-upcasting/deref-upcast-behavioral-change.stderr @@ -1,16 +1,19 @@ -error[E0308]: mismatched types - --> $DIR/deref-upcast-behavioral-change.rs:32:18 +error: this `Deref` implementation is covered by an implicit supertrait coercion + --> $DIR/deref-upcast-behavioral-change.rs:17:1 | -LL | let z: u32 = y; - | --- ^ expected `u32`, found `i32` - | | - | expected due to this +LL | impl<'a> Deref for dyn Foo + 'a { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Foo` implements `Deref>` which conflicts with supertrait `Bar` +... +LL | type Target = dyn Bar + 'a; + | -------------------------------- target type is a supertrait of `dyn Foo` | -help: you can convert an `i32` to a `u32` and panic if the converted value doesn't fit + = warning: this will change its meaning in a future release! + = note: for more information, see issue #89460 +note: the lint level is defined here + --> $DIR/deref-upcast-behavioral-change.rs:1:9 | -LL | let z: u32 = y.try_into().unwrap(); - | ++++++++++++++++++++ +LL | #![deny(deref_into_dyn_supertrait)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/trait-upcasting/diamond.rs b/tests/ui/traits/trait-upcasting/diamond.rs index 9a78339a4ec84..a4f81c464b402 100644 --- a/tests/ui/traits/trait-upcasting/diamond.rs +++ b/tests/ui/traits/trait-upcasting/diamond.rs @@ -1,5 +1,7 @@ // run-pass +#![feature(trait_upcasting)] + trait Foo: PartialEq + std::fmt::Debug + Send + Sync { fn a(&self) -> i32 { 10 diff --git a/tests/ui/traits/trait-upcasting/fewer-associated.rs b/tests/ui/traits/trait-upcasting/fewer-associated.rs index e7ca6fa5208ec..58e72d9d7ef57 100644 --- a/tests/ui/traits/trait-upcasting/fewer-associated.rs +++ b/tests/ui/traits/trait-upcasting/fewer-associated.rs @@ -3,6 +3,8 @@ // revisions: current next //[next] compile-flags: -Znext-solver +#![feature(trait_upcasting)] + trait A: B { type Assoc; } diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr index 119b3109c6323..1538e2f3fd71a 100644 --- a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr +++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/illegal-upcast-from-impl.rs:14:66 + --> $DIR/illegal-upcast-from-impl.rs:16:66 | LL | fn illegal(x: &dyn Sub) -> &dyn Super { x } | ----------------------- ^ expected trait `Super`, found trait `Sub` diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr index 119b3109c6323..1538e2f3fd71a 100644 --- a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr +++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/illegal-upcast-from-impl.rs:14:66 + --> $DIR/illegal-upcast-from-impl.rs:16:66 | LL | fn illegal(x: &dyn Sub) -> &dyn Super { x } | ----------------------- ^ expected trait `Super`, found trait `Sub` diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs index 5a493fd48b3f9..ffed8beb44845 100644 --- a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs +++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs @@ -1,6 +1,8 @@ // revisions: current next //[next] compile-flags: -Znext-solver +#![feature(trait_upcasting)] + trait Super { type Assoc; } diff --git a/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.rs b/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.rs index 999f3b16f50d8..79fb643eacd01 100644 --- a/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.rs +++ b/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.rs @@ -1,4 +1,5 @@ #![deny(deref_into_dyn_supertrait)] +#![feature(trait_upcasting)] // remove this and the test compiles use std::ops::Deref; diff --git a/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.stderr b/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.stderr index fcc80c6148f7d..6b6a26d1593fb 100644 --- a/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.stderr +++ b/tests/ui/traits/trait-upcasting/inference-behavior-change-deref.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/inference-behavior-change-deref.rs:33:18 + --> $DIR/inference-behavior-change-deref.rs:34:18 | LL | let z: u32 = y; | --- ^ expected `u32`, found `i32` diff --git a/tests/ui/traits/trait-upcasting/invalid-upcast.rs b/tests/ui/traits/trait-upcasting/invalid-upcast.rs index 9269a5e3e9ff6..e634bbd5ac6f5 100644 --- a/tests/ui/traits/trait-upcasting/invalid-upcast.rs +++ b/tests/ui/traits/trait-upcasting/invalid-upcast.rs @@ -1,3 +1,5 @@ +#![feature(trait_upcasting)] + trait Foo { fn a(&self) -> i32 { 10 diff --git a/tests/ui/traits/trait-upcasting/invalid-upcast.stderr b/tests/ui/traits/trait-upcasting/invalid-upcast.stderr index e70b99d28c7e4..3aa21ee3dddfb 100644 --- a/tests/ui/traits/trait-upcasting/invalid-upcast.stderr +++ b/tests/ui/traits/trait-upcasting/invalid-upcast.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:51:35 + --> $DIR/invalid-upcast.rs:53:35 | LL | let _: &dyn std::fmt::Debug = baz; | -------------------- ^^^ expected trait `Debug`, found trait `Baz` @@ -10,7 +10,7 @@ LL | let _: &dyn std::fmt::Debug = baz; found reference `&dyn Baz` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:53:24 + --> $DIR/invalid-upcast.rs:55:24 | LL | let _: &dyn Send = baz; | --------- ^^^ expected trait `Send`, found trait `Baz` @@ -21,7 +21,7 @@ LL | let _: &dyn Send = baz; found reference `&dyn Baz` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:55:24 + --> $DIR/invalid-upcast.rs:57:24 | LL | let _: &dyn Sync = baz; | --------- ^^^ expected trait `Sync`, found trait `Baz` @@ -32,7 +32,7 @@ LL | let _: &dyn Sync = baz; found reference `&dyn Baz` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:58:25 + --> $DIR/invalid-upcast.rs:60:25 | LL | let bar: &dyn Bar = baz; | -------- ^^^ expected trait `Bar`, found trait `Baz` @@ -43,7 +43,7 @@ LL | let bar: &dyn Bar = baz; found reference `&dyn Baz` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:60:35 + --> $DIR/invalid-upcast.rs:62:35 | LL | let _: &dyn std::fmt::Debug = bar; | -------------------- ^^^ expected trait `Debug`, found trait `Bar` @@ -54,7 +54,7 @@ LL | let _: &dyn std::fmt::Debug = bar; found reference `&dyn Bar` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:62:24 + --> $DIR/invalid-upcast.rs:64:24 | LL | let _: &dyn Send = bar; | --------- ^^^ expected trait `Send`, found trait `Bar` @@ -65,7 +65,7 @@ LL | let _: &dyn Send = bar; found reference `&dyn Bar` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:64:24 + --> $DIR/invalid-upcast.rs:66:24 | LL | let _: &dyn Sync = bar; | --------- ^^^ expected trait `Sync`, found trait `Bar` @@ -76,7 +76,7 @@ LL | let _: &dyn Sync = bar; found reference `&dyn Bar` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:67:25 + --> $DIR/invalid-upcast.rs:69:25 | LL | let foo: &dyn Foo = baz; | -------- ^^^ expected trait `Foo`, found trait `Baz` @@ -87,7 +87,7 @@ LL | let foo: &dyn Foo = baz; found reference `&dyn Baz` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:69:35 + --> $DIR/invalid-upcast.rs:71:35 | LL | let _: &dyn std::fmt::Debug = foo; | -------------------- ^^^ expected trait `Debug`, found trait `Foo` @@ -98,7 +98,7 @@ LL | let _: &dyn std::fmt::Debug = foo; found reference `&dyn Foo` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:71:24 + --> $DIR/invalid-upcast.rs:73:24 | LL | let _: &dyn Send = foo; | --------- ^^^ expected trait `Send`, found trait `Foo` @@ -109,7 +109,7 @@ LL | let _: &dyn Send = foo; found reference `&dyn Foo` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:73:24 + --> $DIR/invalid-upcast.rs:75:24 | LL | let _: &dyn Sync = foo; | --------- ^^^ expected trait `Sync`, found trait `Foo` @@ -120,7 +120,7 @@ LL | let _: &dyn Sync = foo; found reference `&dyn Foo` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:76:25 + --> $DIR/invalid-upcast.rs:78:25 | LL | let foo: &dyn Foo = bar; | -------- ^^^ expected trait `Foo`, found trait `Bar` @@ -131,7 +131,7 @@ LL | let foo: &dyn Foo = bar; found reference `&dyn Bar` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:78:35 + --> $DIR/invalid-upcast.rs:80:35 | LL | let _: &dyn std::fmt::Debug = foo; | -------------------- ^^^ expected trait `Debug`, found trait `Foo` @@ -142,7 +142,7 @@ LL | let _: &dyn std::fmt::Debug = foo; found reference `&dyn Foo` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:80:24 + --> $DIR/invalid-upcast.rs:82:24 | LL | let _: &dyn Send = foo; | --------- ^^^ expected trait `Send`, found trait `Foo` @@ -153,7 +153,7 @@ LL | let _: &dyn Send = foo; found reference `&dyn Foo` error[E0308]: mismatched types - --> $DIR/invalid-upcast.rs:82:24 + --> $DIR/invalid-upcast.rs:84:24 | LL | let _: &dyn Sync = foo; | --------- ^^^ expected trait `Sync`, found trait `Foo` diff --git a/tests/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs b/tests/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs index 77ce627078f90..b672963ae9887 100644 --- a/tests/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs +++ b/tests/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs @@ -1,4 +1,5 @@ // run-pass +#![feature(trait_upcasting)] struct Test { func: Box, diff --git a/tests/ui/traits/trait-upcasting/issue-11515.current.stderr b/tests/ui/traits/trait-upcasting/issue-11515.current.stderr new file mode 100644 index 0000000000000..da7ac4cc04ebf --- /dev/null +++ b/tests/ui/traits/trait-upcasting/issue-11515.current.stderr @@ -0,0 +1,13 @@ +error[E0658]: cannot cast `dyn Fn()` to `dyn FnMut()`, trait upcasting coercion is experimental + --> $DIR/issue-11515.rs:10:38 + | +LL | let test = Box::new(Test { func: closure }); + | ^^^^^^^ + | + = note: see issue #65991 for more information + = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable + = note: required when coercing `Box<(dyn Fn() + 'static)>` into `Box<(dyn FnMut() + 'static)>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/trait-upcasting/issue-11515.next.stderr b/tests/ui/traits/trait-upcasting/issue-11515.next.stderr new file mode 100644 index 0000000000000..da7ac4cc04ebf --- /dev/null +++ b/tests/ui/traits/trait-upcasting/issue-11515.next.stderr @@ -0,0 +1,13 @@ +error[E0658]: cannot cast `dyn Fn()` to `dyn FnMut()`, trait upcasting coercion is experimental + --> $DIR/issue-11515.rs:10:38 + | +LL | let test = Box::new(Test { func: closure }); + | ^^^^^^^ + | + = note: see issue #65991 for more information + = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable + = note: required when coercing `Box<(dyn Fn() + 'static)>` into `Box<(dyn FnMut() + 'static)>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/trait-upcasting/issue-11515.rs b/tests/ui/traits/trait-upcasting/issue-11515.rs index a1edb53ec37b5..31ea2fb353cd2 100644 --- a/tests/ui/traits/trait-upcasting/issue-11515.rs +++ b/tests/ui/traits/trait-upcasting/issue-11515.rs @@ -1,4 +1,3 @@ -// check-pass // revisions: current next //[next] compile-flags: -Znext-solver @@ -8,5 +7,5 @@ struct Test { fn main() { let closure: Box = Box::new(|| ()); - let test = Box::new(Test { func: closure }); + let test = Box::new(Test { func: closure }); //~ ERROR trait upcasting coercion is experimental [E0658] } diff --git a/tests/ui/traits/trait-upcasting/lifetime.rs b/tests/ui/traits/trait-upcasting/lifetime.rs index 6c65c38870f24..9825158c2dd38 100644 --- a/tests/ui/traits/trait-upcasting/lifetime.rs +++ b/tests/ui/traits/trait-upcasting/lifetime.rs @@ -1,5 +1,7 @@ // run-pass +#![feature(trait_upcasting)] + trait Foo: PartialEq + std::fmt::Debug + Send + Sync { fn a(&self) -> i32 { 10 diff --git a/tests/ui/traits/trait-upcasting/deref-lint-regions.rs b/tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.rs similarity index 52% rename from tests/ui/traits/trait-upcasting/deref-lint-regions.rs rename to tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.rs index 946305cbb2b4b..da1a9cc2775d0 100644 --- a/tests/ui/traits/trait-upcasting/deref-lint-regions.rs +++ b/tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.rs @@ -1,4 +1,4 @@ -// check-pass +#![deny(deref_into_dyn_supertrait)] use std::ops::Deref; @@ -6,7 +6,8 @@ trait Bar<'a> {} trait Foo<'a>: Bar<'a> {} impl<'a> Deref for dyn Foo<'a> { - //~^ WARN this `Deref` implementation is covered by an implicit supertrait coercion + //~^ ERROR this `Deref` implementation is covered by an implicit supertrait coercion + //~| WARN this will change its meaning in a future release! type Target = dyn Bar<'a>; fn deref(&self) -> &Self::Target { diff --git a/tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.stderr b/tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.stderr new file mode 100644 index 0000000000000..a5f3660d4bcb0 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.stderr @@ -0,0 +1,19 @@ +error: this `Deref` implementation is covered by an implicit supertrait coercion + --> $DIR/migrate-lint-deny-regions.rs:8:1 + | +LL | impl<'a> Deref for dyn Foo<'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Foo<'_>` implements `Deref>` which conflicts with supertrait `Bar<'_>` +... +LL | type Target = dyn Bar<'a>; + | -------------------------- target type is a supertrait of `dyn Foo<'_>` + | + = warning: this will change its meaning in a future release! + = note: for more information, see issue #89460 +note: the lint level is defined here + --> $DIR/migrate-lint-deny-regions.rs:1:9 + | +LL | #![deny(deref_into_dyn_supertrait)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/traits/trait-upcasting/deref-lint.rs b/tests/ui/traits/trait-upcasting/migrate-lint-deny.rs similarity index 58% rename from tests/ui/traits/trait-upcasting/deref-lint.rs rename to tests/ui/traits/trait-upcasting/migrate-lint-deny.rs index 68838d2ae20dd..926b3649e01b3 100644 --- a/tests/ui/traits/trait-upcasting/deref-lint.rs +++ b/tests/ui/traits/trait-upcasting/migrate-lint-deny.rs @@ -1,4 +1,4 @@ -// check-pass +#![deny(deref_into_dyn_supertrait)] use std::ops::Deref; @@ -7,7 +7,8 @@ trait A {} trait B: A {} impl<'a> Deref for dyn 'a + B { - //~^ WARN this `Deref` implementation is covered by an implicit supertrait coercion + //~^ ERROR this `Deref` implementation is covered by an implicit supertrait coercion + //~| WARN this will change its meaning in a future release! type Target = dyn A; fn deref(&self) -> &Self::Target { diff --git a/tests/ui/traits/trait-upcasting/migrate-lint-deny.stderr b/tests/ui/traits/trait-upcasting/migrate-lint-deny.stderr new file mode 100644 index 0000000000000..29997a9b3d9c3 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/migrate-lint-deny.stderr @@ -0,0 +1,19 @@ +error: this `Deref` implementation is covered by an implicit supertrait coercion + --> $DIR/migrate-lint-deny.rs:9:1 + | +LL | impl<'a> Deref for dyn 'a + B { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn B` implements `Deref` which conflicts with supertrait `A` +... +LL | type Target = dyn A; + | -------------------- target type is a supertrait of `dyn B` + | + = warning: this will change its meaning in a future release! + = note: for more information, see issue #89460 +note: the lint level is defined here + --> $DIR/migrate-lint-deny.rs:1:9 + | +LL | #![deny(deref_into_dyn_supertrait)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.rs b/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.rs index 2c9126c863d52..8a90a09ff0411 100644 --- a/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.rs +++ b/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.rs @@ -10,6 +10,7 @@ trait Foo: Bar { impl<'a> Deref for dyn Foo + 'a { //~^ WARN this `Deref` implementation is covered by an implicit supertrait coercion + //~| WARN this will change its meaning in a future release! type Target = dyn Bar + 'a; fn deref(&self) -> &Self::Target { diff --git a/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.stderr b/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.stderr index a447f9cf83b7a..6245da5a17604 100644 --- a/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.stderr +++ b/tests/ui/traits/trait-upcasting/migrate-lint-different-substs.stderr @@ -3,11 +3,12 @@ warning: this `Deref` implementation is covered by an implicit supertrait coerci | LL | impl<'a> Deref for dyn Foo + 'a { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Foo` implements `Deref>` which conflicts with supertrait `Bar` -LL | +... LL | type Target = dyn Bar + 'a; | -------------------------------- target type is a supertrait of `dyn Foo` | - = help: consider removing this implementation or replacing it with a method instead + = warning: this will change its meaning in a future release! + = note: for more information, see issue #89460 = note: `#[warn(deref_into_dyn_supertrait)]` on by default warning: 1 warning emitted diff --git a/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs b/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs index 0e17c27671770..2e53a00a90e9c 100644 --- a/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs +++ b/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.rs @@ -1,4 +1,5 @@ // check-fail +#![feature(trait_upcasting)] trait Bar { fn bar(&self, _: T) {} diff --git a/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr b/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr index c888ccc1ebb0d..70ba1fcaf3838 100644 --- a/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr +++ b/tests/ui/traits/trait-upcasting/multiple-occurrence-ambiguousity.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/multiple-occurrence-ambiguousity.rs:19:26 + --> $DIR/multiple-occurrence-ambiguousity.rs:20:26 | LL | let t: &dyn Bar<_> = s; | ----------- ^ expected trait `Bar`, found trait `Foo` diff --git a/tests/ui/traits/trait-upcasting/normalization.rs b/tests/ui/traits/trait-upcasting/normalization.rs index b594969483a8c..24da1ec5dfb58 100644 --- a/tests/ui/traits/trait-upcasting/normalization.rs +++ b/tests/ui/traits/trait-upcasting/normalization.rs @@ -3,6 +3,8 @@ // revisions: current next //[next] compile-flags: -Znext-solver +#![feature(trait_upcasting)] + trait Mirror { type Assoc; } diff --git a/tests/ui/traits/trait-upcasting/replace-vptr.rs b/tests/ui/traits/trait-upcasting/replace-vptr.rs index 4a7304ec2d716..9ccfc9306ac0c 100644 --- a/tests/ui/traits/trait-upcasting/replace-vptr.rs +++ b/tests/ui/traits/trait-upcasting/replace-vptr.rs @@ -1,5 +1,7 @@ // run-pass +#![feature(trait_upcasting)] + trait A { fn foo_a(&self); } diff --git a/tests/ui/traits/trait-upcasting/struct.rs b/tests/ui/traits/trait-upcasting/struct.rs index 64fa9ca1b5fa5..a3e41696956cb 100644 --- a/tests/ui/traits/trait-upcasting/struct.rs +++ b/tests/ui/traits/trait-upcasting/struct.rs @@ -1,5 +1,7 @@ // run-pass +#![feature(trait_upcasting)] + use std::rc::Rc; use std::sync::Arc; diff --git a/tests/ui/traits/trait-upcasting/subtrait-method.rs b/tests/ui/traits/trait-upcasting/subtrait-method.rs index 20277280440c5..136d15af0e8b2 100644 --- a/tests/ui/traits/trait-upcasting/subtrait-method.rs +++ b/tests/ui/traits/trait-upcasting/subtrait-method.rs @@ -1,3 +1,5 @@ +#![feature(trait_upcasting)] + trait Foo: PartialEq + std::fmt::Debug + Send + Sync { fn a(&self) -> i32 { 10 diff --git a/tests/ui/traits/trait-upcasting/subtrait-method.stderr b/tests/ui/traits/trait-upcasting/subtrait-method.stderr index 3fdf3f4816160..918159e845b9e 100644 --- a/tests/ui/traits/trait-upcasting/subtrait-method.stderr +++ b/tests/ui/traits/trait-upcasting/subtrait-method.stderr @@ -1,64 +1,64 @@ error[E0599]: no method named `c` found for reference `&dyn Bar` in the current scope - --> $DIR/subtrait-method.rs:53:9 + --> $DIR/subtrait-method.rs:55:9 | LL | bar.c(); | ^ help: there is a method with a similar name: `a` | = help: items from traits can only be used if the trait is implemented and in scope note: `Baz` defines an item `c`, perhaps you need to implement it - --> $DIR/subtrait-method.rs:25:1 + --> $DIR/subtrait-method.rs:27:1 | LL | trait Baz: Bar { | ^^^^^^^^^^^^^^ error[E0599]: no method named `b` found for reference `&dyn Foo` in the current scope - --> $DIR/subtrait-method.rs:57:9 + --> $DIR/subtrait-method.rs:59:9 | LL | foo.b(); | ^ help: there is a method with a similar name: `a` | = help: items from traits can only be used if the trait is implemented and in scope note: `Bar` defines an item `b`, perhaps you need to implement it - --> $DIR/subtrait-method.rs:15:1 + --> $DIR/subtrait-method.rs:17:1 | LL | trait Bar: Foo { | ^^^^^^^^^^^^^^ error[E0599]: no method named `c` found for reference `&dyn Foo` in the current scope - --> $DIR/subtrait-method.rs:59:9 + --> $DIR/subtrait-method.rs:61:9 | LL | foo.c(); | ^ help: there is a method with a similar name: `a` | = help: items from traits can only be used if the trait is implemented and in scope note: `Baz` defines an item `c`, perhaps you need to implement it - --> $DIR/subtrait-method.rs:25:1 + --> $DIR/subtrait-method.rs:27:1 | LL | trait Baz: Bar { | ^^^^^^^^^^^^^^ error[E0599]: no method named `b` found for reference `&dyn Foo` in the current scope - --> $DIR/subtrait-method.rs:63:9 + --> $DIR/subtrait-method.rs:65:9 | LL | foo.b(); | ^ help: there is a method with a similar name: `a` | = help: items from traits can only be used if the trait is implemented and in scope note: `Bar` defines an item `b`, perhaps you need to implement it - --> $DIR/subtrait-method.rs:15:1 + --> $DIR/subtrait-method.rs:17:1 | LL | trait Bar: Foo { | ^^^^^^^^^^^^^^ error[E0599]: no method named `c` found for reference `&dyn Foo` in the current scope - --> $DIR/subtrait-method.rs:65:9 + --> $DIR/subtrait-method.rs:67:9 | LL | foo.c(); | ^ help: there is a method with a similar name: `a` | = help: items from traits can only be used if the trait is implemented and in scope note: `Baz` defines an item `c`, perhaps you need to implement it - --> $DIR/subtrait-method.rs:25:1 + --> $DIR/subtrait-method.rs:27:1 | LL | trait Baz: Bar { | ^^^^^^^^^^^^^^ diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr index 47ffa68b8ff88..10c22440a8346 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr +++ b/tests/ui/traits/trait-upcasting/type-checking-test-1.current.stderr @@ -1,5 +1,5 @@ error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<_>` - --> $DIR/type-checking-test-1.rs:17:13 + --> $DIR/type-checking-test-1.rs:19:13 | LL | let _ = x as &dyn Bar<_>; // Ambiguous | ^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-1.next.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-1.next.stderr index 47ffa68b8ff88..10c22440a8346 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-1.next.stderr +++ b/tests/ui/traits/trait-upcasting/type-checking-test-1.next.stderr @@ -1,5 +1,5 @@ error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<_>` - --> $DIR/type-checking-test-1.rs:17:13 + --> $DIR/type-checking-test-1.rs:19:13 | LL | let _ = x as &dyn Bar<_>; // Ambiguous | ^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-1.rs b/tests/ui/traits/trait-upcasting/type-checking-test-1.rs index 7d3deeeaa6173..54c3c5e0c28f5 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-1.rs +++ b/tests/ui/traits/trait-upcasting/type-checking-test-1.rs @@ -1,6 +1,8 @@ // revisions: current next //[next] compile-flags: -Znext-solver +#![feature(trait_upcasting)] + trait Foo: Bar + Bar {} trait Bar { fn bar(&self) -> Option { diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-2.rs b/tests/ui/traits/trait-upcasting/type-checking-test-2.rs index b4df0f5a90258..b024b27750bc6 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-2.rs +++ b/tests/ui/traits/trait-upcasting/type-checking-test-2.rs @@ -1,3 +1,5 @@ +#![feature(trait_upcasting)] + trait Foo: Bar + Bar {} trait Bar { fn bar(&self) -> Option { diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr index f84ea93dc6792..3e59b9d33634a 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr +++ b/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr @@ -1,11 +1,11 @@ error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar` - --> $DIR/type-checking-test-2.rs:17:13 + --> $DIR/type-checking-test-2.rs:19:13 | LL | let _ = x as &dyn Bar; // Error | ^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<_>` - --> $DIR/type-checking-test-2.rs:22:13 + --> $DIR/type-checking-test-2.rs:24:13 | LL | let a = x as &dyn Bar<_>; // Ambiguous | ^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-3.rs b/tests/ui/traits/trait-upcasting/type-checking-test-3.rs index 3685569d98d1a..b2db3a127974c 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-3.rs +++ b/tests/ui/traits/trait-upcasting/type-checking-test-3.rs @@ -1,3 +1,5 @@ +#![feature(trait_upcasting)] + trait Foo<'a>: Bar<'a> {} trait Bar<'a> {} diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr index 640a6066268de..e6cb6a753998f 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr +++ b/tests/ui/traits/trait-upcasting/type-checking-test-3.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/type-checking-test-3.rs:9:13 + --> $DIR/type-checking-test-3.rs:11:13 | LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) { | -- lifetime `'a` defined here @@ -7,7 +7,7 @@ LL | let _ = x as &dyn Bar<'a>; // Error | ^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/type-checking-test-3.rs:14:13 + --> $DIR/type-checking-test-3.rs:16:13 | LL | fn test_wrong2<'a>(x: &dyn Foo<'a>) { | -- lifetime `'a` defined here diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-4.rs b/tests/ui/traits/trait-upcasting/type-checking-test-4.rs index 65391502386de..f40c48f0d125f 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-4.rs +++ b/tests/ui/traits/trait-upcasting/type-checking-test-4.rs @@ -1,3 +1,5 @@ +#![feature(trait_upcasting)] + trait Foo<'a>: Bar<'a, 'a> {} trait Bar<'a, 'b> { fn get_b(&self) -> Option<&'a u32> { diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr index 7e7548955d39d..8d506e5807ece 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr +++ b/tests/ui/traits/trait-upcasting/type-checking-test-4.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:13:13 + --> $DIR/type-checking-test-4.rs:15:13 | LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) { | -- lifetime `'a` defined here @@ -7,7 +7,7 @@ LL | let _ = x as &dyn Bar<'static, 'a>; // Error | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:18:13 + --> $DIR/type-checking-test-4.rs:20:13 | LL | fn test_wrong2<'a>(x: &dyn Foo<'static>, y: &'a u32) { | -- lifetime `'a` defined here @@ -15,7 +15,7 @@ LL | let _ = x as &dyn Bar<'a, 'static>; // Error | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:24:5 + --> $DIR/type-checking-test-4.rs:26:5 | LL | fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { | -- lifetime `'a` defined here @@ -24,7 +24,7 @@ LL | y.get_b() // ERROR | ^^^^^^^^^ returning this value requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:29:5 + --> $DIR/type-checking-test-4.rs:31:5 | LL | fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { | -- lifetime `'a` defined here @@ -32,7 +32,7 @@ LL | <_ as Bar>::get_b(x) // ERROR | ^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:34:5 + --> $DIR/type-checking-test-4.rs:36:5 | LL | fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { | -- lifetime `'a` defined here @@ -40,7 +40,7 @@ LL | <_ as Bar<'_, '_>>::get_b(x) // ERROR | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` error: lifetime may not live long enough - --> $DIR/type-checking-test-4.rs:42:5 + --> $DIR/type-checking-test-4.rs:44:5 | LL | fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { | -- lifetime `'a` defined here diff --git a/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.current.stderr b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.current.stderr new file mode 100644 index 0000000000000..f1f0cd3095773 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.current.stderr @@ -0,0 +1,13 @@ +error[E0658]: cannot cast `dyn A` to `dyn B`, trait upcasting coercion is experimental + --> $DIR/upcast-through-struct-tail.rs:10:5 + | +LL | x + | ^ + | + = note: see issue #65991 for more information + = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable + = note: required when coercing `Box>` into `Box>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.next.stderr b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.next.stderr new file mode 100644 index 0000000000000..f1f0cd3095773 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.next.stderr @@ -0,0 +1,13 @@ +error[E0658]: cannot cast `dyn A` to `dyn B`, trait upcasting coercion is experimental + --> $DIR/upcast-through-struct-tail.rs:10:5 + | +LL | x + | ^ + | + = note: see issue #65991 for more information + = help: add `#![feature(trait_upcasting)]` to the crate attributes to enable + = note: required when coercing `Box>` into `Box>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.rs b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.rs index f8cf793e4a49c..948f058e5287b 100644 --- a/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.rs +++ b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.rs @@ -1,4 +1,3 @@ -// check-pass // revisions: current next //[next] compile-flags: -Znext-solver @@ -9,6 +8,7 @@ trait B {} fn test<'a>(x: Box>) -> Box> { x + //~^ ERROR cannot cast `dyn A` to `dyn B`, trait upcasting coercion is experimental } fn main() {} diff --git a/tests/ui/traits/upcast_soundness_bug.rs b/tests/ui/traits/upcast_soundness_bug.rs new file mode 100644 index 0000000000000..32e32850925f7 --- /dev/null +++ b/tests/ui/traits/upcast_soundness_bug.rs @@ -0,0 +1,69 @@ +#![feature(trait_upcasting)] +// known-bug: #120222 +// check-pass +//! This will segfault at runtime. + +pub trait SupSupA { + fn method(&self) {} +} +pub trait SupSupB {} +impl SupSupA for T {} +impl SupSupB for T {} + +pub trait Super: SupSupA + SupSupB {} + +pub trait Unimplemented {} + +pub trait Trait: Super + Super { + fn missing_method(&self) + where + T1: Unimplemented, + { + } +} + +impl Super for S {} + +impl Trait for S {} + +#[inline(never)] +pub fn user1() -> &'static dyn Trait { + &() + /* VTABLE: + .L__unnamed_2: + .quad core::ptr::drop_in_place<()> + .asciz "\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000" + .quad example::SupSupA::method + .quad .L__unnamed_4 // SupSupB vtable (pointer) + .zero 8 // null pointer for missing_method + */ +} + +#[inline(never)] +pub fn user2() -> &'static dyn Trait { + &() + /* VTABLE: + .L__unnamed_3: + .quad core::ptr::drop_in_place<()> + .asciz "\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000" + .quad example::SupSupA::method + .quad .L__unnamed_4 // SupSupB vtable (pointer) + .quad .L__unnamed_5 // Super vtable (pointer) + .zero 8 // null pointer for missing_method + */ +} + +fn main() { + let p: *const dyn Trait = &(); + let p = p as *const dyn Trait; // <- this is bad! + let p = p as *const dyn Super; // <- this upcast accesses improper vtable entry + // accessing from L__unnamed_2 the position for the 'Super vtable (pointer)', + // thus reading 'null pointer for missing_method' + + let p = p as *const dyn SupSupB; // <- this upcast dereferences (null) pointer from that entry + // to read the SupSupB vtable (pointer) + + // SEGFAULT + + println!("{:?}", p); +}