From f2ef88ba064cd6799922e85ae0748d298ad436d1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 19 Jan 2024 21:28:37 +0000 Subject: [PATCH 01/13] Consolidate logic around resolving built-in coroutine trait impls --- compiler/rustc_hir/src/lang_items.rs | 3 ++ compiler/rustc_middle/src/ty/instance.rs | 50 ++++++++++++++++++++ compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_ty_utils/src/instance.rs | 59 +----------------------- library/core/src/ops/coroutine.rs | 1 + 5 files changed, 56 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 1cc1f11b3c858..85d10872b3d1d 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -213,8 +213,11 @@ language_item_table! { Iterator, sym::iterator, iterator_trait, Target::Trait, GenericRequirement::Exact(0); Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0); AsyncIterator, sym::async_iterator, async_iterator_trait, Target::Trait, GenericRequirement::Exact(0); + CoroutineState, sym::coroutine_state, coroutine_state, Target::Enum, GenericRequirement::None; Coroutine, sym::coroutine, coroutine_trait, Target::Trait, GenericRequirement::Minimum(1); + CoroutineResume, sym::coroutine_resume, coroutine_resume, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; + Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None; Pin, sym::pin, pin_type, Target::Struct, GenericRequirement::None; diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index dd41cb5a61f44..b6c3c34078f76 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -3,6 +3,7 @@ use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable}; use crate::ty::{EarlyBinder, GenericArgs, GenericArgsRef, TypeVisitableExt}; use rustc_errors::ErrorGuaranteed; +use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::lang_items::LangItem; @@ -11,6 +12,7 @@ use rustc_macros::HashStable; use rustc_middle::ty::normalize_erasing_regions::NormalizationError; use rustc_span::Symbol; +use std::assert_matches::assert_matches; use std::fmt; /// A monomorphized `InstanceDef`. @@ -572,6 +574,54 @@ impl<'tcx> Instance<'tcx> { Some(Instance { def, args }) } + pub fn try_resolve_item_for_coroutine( + tcx: TyCtxt<'tcx>, + trait_item_id: DefId, + trait_id: DefId, + rcvr_args: ty::GenericArgsRef<'tcx>, + ) -> Option> { + let ty::Coroutine(coroutine_def_id, args) = *rcvr_args.type_at(0).kind() else { + return None; + }; + let coroutine_kind = tcx.coroutine_kind(coroutine_def_id).unwrap(); + + let lang_items = tcx.lang_items(); + let coroutine_callable_item = if Some(trait_id) == lang_items.future_trait() { + assert_matches!( + coroutine_kind, + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) + ); + hir::LangItem::FuturePoll + } else if Some(trait_id) == lang_items.iterator_trait() { + assert_matches!( + coroutine_kind, + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) + ); + hir::LangItem::IteratorNext + } else if Some(trait_id) == lang_items.async_iterator_trait() { + assert_matches!( + coroutine_kind, + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) + ); + hir::LangItem::AsyncIteratorPollNext + } else if Some(trait_id) == lang_items.coroutine_trait() { + assert_matches!(coroutine_kind, hir::CoroutineKind::Coroutine(_)); + hir::LangItem::CoroutineResume + } else { + return None; + }; + + if tcx.lang_items().get(coroutine_callable_item) == Some(trait_item_id) { + Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args: args }) + } else { + // All other methods should be defaulted methods of the built-in trait. + // This is important for `Iterator`'s combinators, but also useful for + // adding future default methods to `Future`, for instance. + debug_assert!(tcx.defaultness(trait_item_id).has_value()); + Some(Instance::new(trait_item_id, rcvr_args)) + } + } + /// Depending on the kind of `InstanceDef`, the MIR body associated with an /// instance is expressed in terms of the generic parameters of `self.def_id()`, and in other /// cases the MIR body is expressed in terms of the types found in the substitution array. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 44795022cbab3..bebeecebbb643 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -600,6 +600,7 @@ symbols! { core_panic_macro, coroutine, coroutine_clone, + coroutine_resume, coroutine_state, coroutines, cosf32, diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 81d5304b81265..e5e31f7caaa2b 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -245,63 +245,6 @@ fn resolve_associated_item<'tcx>( span: tcx.def_span(trait_item_id), }) } - } else if Some(trait_ref.def_id) == lang_items.future_trait() { - let ty::Coroutine(coroutine_def_id, args) = *rcvr_args.type_at(0).kind() else { - bug!() - }; - if Some(trait_item_id) == tcx.lang_items().future_poll_fn() { - // `Future::poll` is generated by the compiler. - Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args: args }) - } else { - // All other methods are default methods of the `Future` trait. - // (this assumes that `ImplSource::Builtin` is only used for methods on `Future`) - debug_assert!(tcx.defaultness(trait_item_id).has_value()); - Some(Instance::new(trait_item_id, rcvr_args)) - } - } else if Some(trait_ref.def_id) == lang_items.iterator_trait() { - let ty::Coroutine(coroutine_def_id, args) = *rcvr_args.type_at(0).kind() else { - bug!() - }; - if Some(trait_item_id) == tcx.lang_items().next_fn() { - // `Iterator::next` is generated by the compiler. - Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args }) - } else { - // All other methods are default methods of the `Iterator` trait. - // (this assumes that `ImplSource::Builtin` is only used for methods on `Iterator`) - debug_assert!(tcx.defaultness(trait_item_id).has_value()); - Some(Instance::new(trait_item_id, rcvr_args)) - } - } else if Some(trait_ref.def_id) == lang_items.async_iterator_trait() { - let ty::Coroutine(coroutine_def_id, args) = *rcvr_args.type_at(0).kind() else { - bug!() - }; - - if cfg!(debug_assertions) && tcx.item_name(trait_item_id) != sym::poll_next { - span_bug!( - tcx.def_span(coroutine_def_id), - "no definition for `{trait_ref}::{}` for built-in coroutine type", - tcx.item_name(trait_item_id) - ) - } - - // `AsyncIterator::poll_next` is generated by the compiler. - Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args }) - } else if Some(trait_ref.def_id) == lang_items.coroutine_trait() { - let ty::Coroutine(coroutine_def_id, args) = *rcvr_args.type_at(0).kind() else { - bug!() - }; - if cfg!(debug_assertions) && tcx.item_name(trait_item_id) != sym::resume { - // For compiler developers who'd like to add new items to `Coroutine`, - // you either need to generate a shim body, or perhaps return - // `InstanceDef::Item` pointing to a trait default method body if - // it is given a default implementation by the trait. - span_bug!( - tcx.def_span(coroutine_def_id), - "no definition for `{trait_ref}::{}` for built-in coroutine type", - tcx.item_name(trait_item_id) - ) - } - Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args }) } else if tcx.fn_trait_kind_from_def_id(trait_ref.def_id).is_some() { // FIXME: This doesn't check for malformed libcore that defines, e.g., // `trait Fn { fn call_once(&self) { .. } }`. This is mostly for extension @@ -334,7 +277,7 @@ fn resolve_associated_item<'tcx>( ), } } else { - None + Instance::try_resolve_item_for_coroutine(tcx, trait_item_id, trait_id, rcvr_args) } } traits::ImplSource::Param(..) diff --git a/library/core/src/ops/coroutine.rs b/library/core/src/ops/coroutine.rs index e58c9068af85c..6faded76a4a49 100644 --- a/library/core/src/ops/coroutine.rs +++ b/library/core/src/ops/coroutine.rs @@ -111,6 +111,7 @@ pub trait Coroutine { /// been returned previously. While coroutine literals in the language are /// guaranteed to panic on resuming after `Complete`, this is not guaranteed /// for all implementations of the `Coroutine` trait. + #[cfg_attr(not(bootstrap), lang = "coroutine_resume")] fn resume(self: Pin<&mut Self>, arg: R) -> CoroutineState; } From c3e4c457fef26e669ce336176e7a878baaaeda9b Mon Sep 17 00:00:00 2001 From: jyn Date: Fri, 19 Jan 2024 18:09:54 -0500 Subject: [PATCH 02/13] Track `verbose` and `verbose_internals` bjorn3 says: > On errors we don't finalize the incr comp cache, but non-fatal diagnostics are cached afaik. Otherwise we would have to replay the query in question, which we may not be able to do if the query key is not reconstructible from the dep node fingerprint. So we must track these flags to avoid replaying incorrect diagnostics. --- compiler/rustc_interface/src/tests.rs | 3 ++- compiler/rustc_session/src/options.rs | 4 ++-- tests/incremental/commandline-args.rs | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 555c822ad6d68..2d4963a8b901a 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -98,6 +98,7 @@ fn assert_same_hash(x: &Options, y: &Options) { assert_same_clone(y); } +#[track_caller] fn assert_different_hash(x: &Options, y: &Options) { assert_ne!(x.dep_tracking_hash(true), y.dep_tracking_hash(true)); assert_ne!(x.dep_tracking_hash(false), y.dep_tracking_hash(false)); @@ -713,7 +714,6 @@ fn test_unstable_options_tracking_hash() { untracked!(unpretty, Some("expanded".to_string())); untracked!(unstable_options, true); untracked!(validate_mir, true); - untracked!(verbose_internals, true); untracked!(write_long_types_to_disk, false); // tidy-alphabetical-end @@ -845,6 +845,7 @@ fn test_unstable_options_tracking_hash() { }; } tracked_no_crate_hash!(no_codegen, true); + tracked_no_crate_hash!(verbose_internals, true); } #[test] diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 1337ade62c019..486b6d4bf2e14 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -224,7 +224,7 @@ top_level_options!( working_dir: RealFileName [TRACKED], color: ColorConfig [UNTRACKED], - verbose: bool [UNTRACKED], + verbose: bool [TRACKED_NO_CRATE_HASH], } ); @@ -1986,7 +1986,7 @@ written to standard error output)"), validate_mir: bool = (false, parse_bool, [UNTRACKED], "validate MIR after each transformation"), #[rustc_lint_opt_deny_field_access("use `Session::verbose_internals` instead of this field")] - verbose_internals: bool = (false, parse_bool, [UNTRACKED], + verbose_internals: bool = (false, parse_bool, [TRACKED_NO_CRATE_HASH], "in general, enable more debug printouts (default: no)"), #[rustc_lint_opt_deny_field_access("use `Session::verify_llvm_ir` instead of this field")] verify_llvm_ir: bool = (false, parse_bool, [TRACKED], diff --git a/tests/incremental/commandline-args.rs b/tests/incremental/commandline-args.rs index e17e6feae0745..7a4c33d36e410 100644 --- a/tests/incremental/commandline-args.rs +++ b/tests/incremental/commandline-args.rs @@ -11,13 +11,13 @@ #![rustc_partition_codegened(module="commandline_args", cfg="rpass4")] // Between revisions 1 and 2, we are changing the debuginfo-level, which should -// invalidate the cache. Between revisions 2 and 3, we are adding `--verbose` +// invalidate the cache. Between revisions 2 and 3, we are adding `--diagnostic-width` // which should have no effect on the cache. Between revisions, we are adding // `--remap-path-prefix` which should invalidate the cache: //[rpass1] compile-flags: -C debuginfo=0 //[rpass2] compile-flags: -C debuginfo=2 -//[rpass3] compile-flags: -C debuginfo=2 --verbose -//[rpass4] compile-flags: -C debuginfo=2 --verbose --remap-path-prefix=/home/bors/rust=src +//[rpass3] compile-flags: -C debuginfo=2 --diagnostic-width=80 +//[rpass4] compile-flags: -C debuginfo=2 --diagnostic-width=80 --remap-path-prefix=/home/bors/r=src pub fn main() { // empty From 012a304a167aa4bafe91f40cc73ed4bb0073877c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 22 Jan 2024 11:00:30 +1100 Subject: [PATCH 03/13] Fix a `trimmed_def_paths` assertion failure. `RegionHighlightMode::force_print_trimmed_def_path` can call `trimmed_def_paths` even when `tcx.sess.opts.trimmed_def_paths` is false. Based on the `force` in the method name, it seems this is deliberate, so I have removed the assertion. Fixes #120035. --- compiler/rustc_middle/src/ty/print/pretty.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 4028de27cae14..a06f4c6ba12ea 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3072,8 +3072,6 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N /// See also [`DelayDm`](rustc_error_messages::DelayDm) and [`with_no_trimmed_paths!`]. // this is pub to be able to intra-doc-link it pub fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> DefIdMap { - assert!(tcx.sess.opts.trimmed_def_paths); - // Trimming paths is expensive and not optimized, since we expect it to only be used for error // reporting. // From c4fc9ff0d30a56dae9ca1ba44e407d20f21e6516 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 22 Jan 2024 13:31:52 +1100 Subject: [PATCH 04/13] Document `Token{Stream,Tree}::Display` more thoroughly. To expressly warn against the kind of proc macro implementation that was broken in #119875. --- library/proc_macro/src/lib.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index ca83e2be5c147..87e89a464bc1a 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -191,6 +191,14 @@ impl ToString for TokenStream { /// Prints the token stream as a string that is supposed to be losslessly convertible back /// into the same token stream (modulo spans), except for possibly `TokenTree::Group`s /// with `Delimiter::None` delimiters and negative numeric literals. +/// +/// Note: the exact form of the output is subject to change, e.g. there might +/// be changes in the whitespace used between tokens. Therefore, you should +/// *not* do any kind of simple substring matching on the output string (as +/// produced by `to_string`) to implement a proc macro, because that matching +/// might stop working if such changes happen. Instead, you should work at the +/// `TokenTree` level, e.g. matching against `TokenTree::Ident`, +/// `TokenTree::Punct`, or `TokenTree::Literal`. #[stable(feature = "proc_macro_lib", since = "1.15.0")] impl fmt::Display for TokenStream { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -758,6 +766,14 @@ impl ToString for TokenTree { /// Prints the token tree as a string that is supposed to be losslessly convertible back /// into the same token tree (modulo spans), except for possibly `TokenTree::Group`s /// with `Delimiter::None` delimiters and negative numeric literals. +/// +/// Note: the exact form of the output is subject to change, e.g. there might +/// be changes in the whitespace used between tokens. Therefore, you should +/// *not* do any kind of simple substring matching on the output string (as +/// produced by `to_string`) to implement a proc macro, because that matching +/// might stop working if such changes happen. Instead, you should work at the +/// `TokenTree` level, e.g. matching against `TokenTree::Ident`, +/// `TokenTree::Punct`, or `TokenTree::Literal`. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl fmt::Display for TokenTree { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { From e74c667a53c6368579867a74494e6fb7a7f17d13 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 6 Jan 2024 16:07:27 +0000 Subject: [PATCH 05/13] Fix msys2 tty detection for /dev/ptmx Our "true negative" detection assumes that if at least one std handle is a Windows console then no other handle will be a msys2 tty pipe. This turns out to be a faulty assumption in the case of `/dev/ptmx`. --- library/std/src/sys/pal/windows/io.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/library/std/src/sys/pal/windows/io.rs b/library/std/src/sys/pal/windows/io.rs index 649826d25cef7..b73d9f3ff4c4a 100644 --- a/library/std/src/sys/pal/windows/io.rs +++ b/library/std/src/sys/pal/windows/io.rs @@ -97,20 +97,6 @@ unsafe fn handle_is_console(handle: BorrowedHandle<'_>) -> bool { return true; } - // At this point, we *could* have a false negative. We can determine that this is a true - // negative if we can detect the presence of a console on any of the standard I/O streams. If - // another stream has a console, then we know we're in a Windows console and can therefore - // trust the negative. - for std_handle in [c::STD_INPUT_HANDLE, c::STD_OUTPUT_HANDLE, c::STD_ERROR_HANDLE] { - let std_handle = c::GetStdHandle(std_handle); - if !std_handle.is_null() - && std_handle != handle - && c::GetConsoleMode(std_handle, &mut out) != 0 - { - return false; - } - } - // Otherwise, we fall back to an msys hack to see if we can detect the presence of a pty. msys_tty_on(handle) } From dbc1f074bc0958df74bda0f7b8d0f185c2070dea Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 18 Jan 2024 17:43:27 +0100 Subject: [PATCH 06/13] Tweak --- compiler/rustc_hir_typeck/src/expr.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index aca17ec77a4bb..4167c417d8332 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -208,10 +208,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // without the final expr (e.g. `try { return; }`). We don't want to generate an // unreachable_code lint for it since warnings for autogenerated code are confusing. let is_try_block_generated_unit_expr = match expr.kind { - ExprKind::Call(_, args) if expr.span.is_desugaring(DesugaringKind::TryBlock) => { - args.len() == 1 && args[0].span.is_desugaring(DesugaringKind::TryBlock) + ExprKind::Call(_, [arg]) => { + expr.span.is_desugaring(DesugaringKind::TryBlock) + && arg.span.is_desugaring(DesugaringKind::TryBlock) } - _ => false, }; From a9ea07d17c329f5a36e01826f704c16093d02f14 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 18 Jan 2024 16:16:30 +0100 Subject: [PATCH 07/13] Never pattern in function arguments diverges --- compiler/rustc_hir_typeck/src/check.rs | 10 +++- compiler/rustc_hir_typeck/src/expr.rs | 9 ++- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 9 +++ .../diverge-causes-unreachable-code.rs | 35 ++++++++++++ .../diverge-causes-unreachable-code.stderr | 38 +++++++++++++ .../rfc-0000-never_patterns/diverges-not.rs | 56 +++++++++++++++++++ .../diverges-not.stderr | 55 ++++++++++++++++++ .../rfcs/rfc-0000-never_patterns/diverges.rs | 29 ++++++++++ 8 files changed, 238 insertions(+), 3 deletions(-) create mode 100644 tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.rs create mode 100644 tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr create mode 100644 tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs create mode 100644 tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.stderr create mode 100644 tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index c887368b2a233..4d9f5b831c161 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -2,8 +2,7 @@ use std::cell::RefCell; use crate::coercion::CoerceMany; use crate::gather_locals::GatherLocalsVisitor; -use crate::CoroutineTypes; -use crate::FnCtxt; +use crate::{CoroutineTypes, Diverges, FnCtxt}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::intravisit::Visitor; @@ -76,6 +75,12 @@ pub(super) fn check_fn<'a, 'tcx>( let ty: Option<&hir::Ty<'_>> = try { inputs_hir?.get(idx)? }; let ty_span = ty.map(|ty| ty.span); fcx.check_pat_top(param.pat, param_ty, ty_span, None, None); + if param.pat.is_never_pattern() { + fcx.function_diverges_because_of_empty_arguments.set(Diverges::Always { + span: param.pat.span, + custom_note: Some("any code following a never pattern is unreachable"), + }); + } // Check that argument is Sized. if !params_can_be_unsized { @@ -105,6 +110,7 @@ pub(super) fn check_fn<'a, 'tcx>( hir::FnRetTy::Return(ty) => ty.span, }; fcx.require_type_is_sized(declared_ret_ty, return_or_body_span, traits::SizedReturnType); + fcx.is_whole_body.set(true); fcx.check_return_expr(body.value, false); // Finalize the return check by taking the LUB of the return types diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 4167c417d8332..3be37d1a3be13 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -220,9 +220,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.warn_if_unreachable(expr.hir_id, expr.span, "expression"); } - // Hide the outer diverging and has_errors flags. + // Whether a past expression diverges doesn't affect typechecking of this expression, so we + // reset `diverges` while checking `expr`. let old_diverges = self.diverges.replace(Diverges::Maybe); + if self.is_whole_body.replace(false) { + // If this expression is the whole body and the function diverges because of its + // arguments, we check this here to ensure the body is considered to diverge. + self.diverges.set(self.function_diverges_because_of_empty_arguments.get()) + }; + let ty = ensure_sufficient_stack(|| match &expr.kind { hir::ExprKind::Path( qpath @ (hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)), diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index e6c2091d85add..f65e9b698ab2a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -103,6 +103,13 @@ pub struct FnCtxt<'a, 'tcx> { /// the diverges flag is set to something other than `Maybe`. pub(super) diverges: Cell, + /// If one of the function arguments is a never pattern, this counts as diverging code. This + /// affect typechecking of the function body. + pub(super) function_diverges_because_of_empty_arguments: Cell, + + /// Whether the currently checked node is the whole body of the function. + pub(super) is_whole_body: Cell, + pub(super) enclosing_breakables: RefCell>, pub(super) inh: &'a Inherited<'tcx>, @@ -124,6 +131,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ret_coercion_span: Cell::new(None), coroutine_types: None, diverges: Cell::new(Diverges::Maybe), + function_diverges_because_of_empty_arguments: Cell::new(Diverges::Maybe), + is_whole_body: Cell::new(false), enclosing_breakables: RefCell::new(EnclosingBreakables { stack: Vec::new(), by_id: Default::default(), diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.rs b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.rs new file mode 100644 index 0000000000000..5c852c8adcccf --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.rs @@ -0,0 +1,35 @@ +#![feature(never_patterns)] +#![allow(incomplete_features)] +#![deny(unreachable_patterns)] +#![deny(unreachable_code)] + +fn main() {} + +enum Void {} + +fn never_arg(!: Void) -> u32 { + println!(); + //~^ ERROR unreachable statement +} + +fn ref_never_arg(&!: &Void) -> u32 { + println!(); + //~^ ERROR unreachable statement +} + +//fn never_let() -> u32 { +// let ptr: *const Void = std::ptr::null(); +// unsafe { +// let ! = *ptr; +// } +// println!(); +//} + +fn never_match() -> u32 { + let ptr: *const Void = std::ptr::null(); + unsafe { + match *ptr { ! }; + } + println!(); + //~^ ERROR unreachable statement +} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr new file mode 100644 index 0000000000000..c9cd3f53944e4 --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr @@ -0,0 +1,38 @@ +error: unreachable statement + --> $DIR/diverge-causes-unreachable-code.rs:11:5 + | +LL | fn never_arg(!: Void) -> u32 { + | - any code following a never pattern is unreachable +LL | println!(); + | ^^^^^^^^^^ unreachable statement + | +note: the lint level is defined here + --> $DIR/diverge-causes-unreachable-code.rs:4:9 + | +LL | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::print` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unreachable statement + --> $DIR/diverge-causes-unreachable-code.rs:16:5 + | +LL | fn ref_never_arg(&!: &Void) -> u32 { + | -- any code following a never pattern is unreachable +LL | println!(); + | ^^^^^^^^^^ unreachable statement + | + = note: this error originates in the macro `$crate::print` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unreachable statement + --> $DIR/diverge-causes-unreachable-code.rs:33:5 + | +LL | match *ptr { ! }; + | ---------------- any code following this `match` expression is unreachable, as all arms diverge +LL | } +LL | println!(); + | ^^^^^^^^^^ unreachable statement + | + = note: this error originates in the macro `$crate::print` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs b/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs new file mode 100644 index 0000000000000..6b85ada3aadee --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs @@ -0,0 +1,56 @@ +#![feature(never_patterns)] +#![feature(let_chains)] +#![allow(incomplete_features)] +#![deny(unreachable_patterns)] + +fn main() {} + +enum Void {} + +// Contrast with `./diverges.rs`: merely having an empty type around isn't enough to diverge. + +fn wild_void(_: Void) -> u32 {} +//~^ ERROR: mismatched types + +fn wild_let() -> u32 { + let ptr: *const Void = std::ptr::null(); + unsafe { + //~^ ERROR: mismatched types + let _ = *ptr; + } +} + +fn wild_match() -> u32 { + let ptr: *const Void = std::ptr::null(); + unsafe { + match *ptr { + _ => {} //~ ERROR: mismatched types + } + } +} + +fn binding_void(_x: Void) -> u32 {} +//~^ ERROR: mismatched types + +fn binding_let() -> u32 { + let ptr: *const Void = std::ptr::null(); + unsafe { + //~^ ERROR: mismatched types + let _x = *ptr; + } +} + +fn binding_match() -> u32 { + let ptr: *const Void = std::ptr::null(); + unsafe { + match *ptr { + _x => {} //~ ERROR: mismatched types + } + } +} + +// Don't confuse this with a `let !` statement. +fn let_chain(x: Void) -> u32 { + if let true = true && let ! = x {} + //~^ ERROR: mismatched types +} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.stderr new file mode 100644 index 0000000000000..08a1bbe9bffac --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.stderr @@ -0,0 +1,55 @@ +error[E0308]: mismatched types + --> $DIR/diverges-not.rs:12:26 + | +LL | fn wild_void(_: Void) -> u32 {} + | --------- ^^^ expected `u32`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + +error[E0308]: mismatched types + --> $DIR/diverges-not.rs:17:5 + | +LL | / unsafe { +LL | | +LL | | let _ = *ptr; +LL | | } + | |_____^ expected `u32`, found `()` + +error[E0308]: mismatched types + --> $DIR/diverges-not.rs:27:18 + | +LL | _ => {} + | ^^ expected `u32`, found `()` + +error[E0308]: mismatched types + --> $DIR/diverges-not.rs:32:30 + | +LL | fn binding_void(_x: Void) -> u32 {} + | ------------ ^^^ expected `u32`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + +error[E0308]: mismatched types + --> $DIR/diverges-not.rs:37:5 + | +LL | / unsafe { +LL | | +LL | | let _x = *ptr; +LL | | } + | |_____^ expected `u32`, found `()` + +error[E0308]: mismatched types + --> $DIR/diverges-not.rs:47:19 + | +LL | _x => {} + | ^^ expected `u32`, found `()` + +error[E0308]: mismatched types + --> $DIR/diverges-not.rs:54:37 + | +LL | if let true = true && let ! = x {} + | ^^ expected `u32`, found `()` + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs b/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs new file mode 100644 index 0000000000000..40aa2bd29e594 --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs @@ -0,0 +1,29 @@ +// check-pass +#![feature(never_patterns)] +#![allow(incomplete_features)] +#![deny(unreachable_patterns)] + +fn main() {} + +enum Void {} + +// A never pattern alone diverges. + +fn never_arg(!: Void) -> u32 {} + +fn ref_never_arg(&!: &Void) -> u32 {} + +// fn never_let() -> u32 { +// let ptr: *const Void = std::ptr::null(); +// unsafe { +// let ! = *ptr; +// } +// } + +fn never_match() -> u32 { + let ptr: *const Void = std::ptr::null(); + unsafe { + match *ptr { ! }; + } + println!(); // Ensures this typechecks because of divergence. +} From d1f1075931983be0a2ae91905fe8a6da50149d3d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 18 Jan 2024 18:22:08 +0100 Subject: [PATCH 08/13] Never pattern in `let` statement diverges --- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 6 ++++++ .../diverge-causes-unreachable-code.rs | 15 ++++++++------- .../diverge-causes-unreachable-code.stderr | 15 +++++++++++++-- tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs | 12 ++++++------ 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index ddb4224b60db1..136ed1a709e94 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1471,6 +1471,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Type check a `let` statement. pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) { self.check_decl(local.into()); + if local.pat.is_never_pattern() { + self.diverges.set(Diverges::Always { + span: local.pat.span, + custom_note: Some("any code following a never pattern is unreachable"), + }); + } } pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>) { diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.rs b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.rs index 5c852c8adcccf..f7e4007b920d9 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.rs +++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.rs @@ -17,13 +17,14 @@ fn ref_never_arg(&!: &Void) -> u32 { //~^ ERROR unreachable statement } -//fn never_let() -> u32 { -// let ptr: *const Void = std::ptr::null(); -// unsafe { -// let ! = *ptr; -// } -// println!(); -//} +fn never_let() -> u32 { + let ptr: *const Void = std::ptr::null(); + unsafe { + let ! = *ptr; + } + println!(); + //~^ ERROR unreachable statement +} fn never_match() -> u32 { let ptr: *const Void = std::ptr::null(); diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr index c9cd3f53944e4..c33a5855d5068 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr +++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverge-causes-unreachable-code.stderr @@ -24,7 +24,18 @@ LL | println!(); = note: this error originates in the macro `$crate::print` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: unreachable statement - --> $DIR/diverge-causes-unreachable-code.rs:33:5 + --> $DIR/diverge-causes-unreachable-code.rs:25:5 + | +LL | let ! = *ptr; + | - any code following a never pattern is unreachable +LL | } +LL | println!(); + | ^^^^^^^^^^ unreachable statement + | + = note: this error originates in the macro `$crate::print` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unreachable statement + --> $DIR/diverge-causes-unreachable-code.rs:34:5 | LL | match *ptr { ! }; | ---------------- any code following this `match` expression is unreachable, as all arms diverge @@ -34,5 +45,5 @@ LL | println!(); | = note: this error originates in the macro `$crate::print` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs b/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs index 40aa2bd29e594..6f4b81b9b25b0 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs +++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs @@ -13,12 +13,12 @@ fn never_arg(!: Void) -> u32 {} fn ref_never_arg(&!: &Void) -> u32 {} -// fn never_let() -> u32 { -// let ptr: *const Void = std::ptr::null(); -// unsafe { -// let ! = *ptr; -// } -// } +fn never_let() -> u32 { + let ptr: *const Void = std::ptr::null(); + unsafe { + let ! = *ptr; + } +} fn never_match() -> u32 { let ptr: *const Void = std::ptr::null(); From 9a20cf169792bd9a3f7edcb5ac27d89598f32616 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 22 Jan 2024 12:23:50 +0000 Subject: [PATCH 09/13] Revert "Auto merge of #118133 - Urgau:stabilize_trait_upcasting, r=WaffleLapkin" This reverts commit 6d2b84b3ed7848fd91b8d6151d4451b3103ed816, reversing changes made to 73bc12199ea8c7651ed98b069c0dd6b0bb5fabcf. --- compiler/rustc_feature/src/accepted.rs | 3 -- compiler/rustc_feature/src/unstable.rs | 3 ++ compiler/rustc_hir_typeck/src/coercion.rs | 23 +++++++++ .../src/deref_into_dyn_supertrait.rs | 13 ++++- compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_lint/src/lints.rs | 1 - compiler/rustc_middle/src/lib.rs | 1 + .../src/traits/select/candidate_assembly.rs | 51 +++++++++++++++++++ library/core/tests/lib.rs | 1 + .../src/language-features/trait-upcasting.md | 27 ++++++++++ src/tools/miri/src/lib.rs | 2 +- .../tests/fail/dyn-upcast-trait-mismatch.rs | 3 ++ src/tools/miri/tests/pass/box-custom-alloc.rs | 3 +- src/tools/miri/tests/pass/dyn-upcast.rs | 3 ++ tests/ui/codegen/issue-99551.rs | 1 + .../ui/dyn-star/no-unsize-coerce-dyn-trait.rs | 2 +- .../no-unsize-coerce-dyn-trait.stderr | 2 +- tests/ui/dyn-star/upcast.rs | 2 +- tests/ui/dyn-star/upcast.stderr | 2 +- .../feature-gate-trait_upcasting.rs | 13 +++++ .../feature-gate-trait_upcasting.stderr | 14 +++++ .../next-solver/normalize-unsize-rhs.rs | 1 + .../trait-upcast-lhs-needs-normalization.rs | 1 + .../traits/next-solver/upcast-right-substs.rs | 1 + .../alias-where-clause-isnt-supertrait.rs | 1 + .../alias-where-clause-isnt-supertrait.stderr | 2 +- tests/ui/traits/trait-upcasting/basic.rs | 2 + .../correct-supertrait-substitution.rs | 1 + .../trait-upcasting/deref-lint-regions.stderr | 14 ----- .../traits/trait-upcasting/deref-lint.stderr | 14 ----- .../deref-upcast-behavioral-change.rs | 3 +- .../deref-upcast-behavioral-change.stderr | 23 +++++---- tests/ui/traits/trait-upcasting/diamond.rs | 2 + .../trait-upcasting/fewer-associated.rs | 2 + .../illegal-upcast-from-impl.current.stderr | 2 +- .../illegal-upcast-from-impl.next.stderr | 2 +- .../illegal-upcast-from-impl.rs | 2 + .../inference-behavior-change-deref.rs | 1 + .../inference-behavior-change-deref.stderr | 2 +- .../traits/trait-upcasting/invalid-upcast.rs | 2 + .../trait-upcasting/invalid-upcast.stderr | 30 +++++------ .../issue-11515-upcast-fn_mut-fn.rs | 1 + .../issue-11515.current.stderr | 14 +++++ .../trait-upcasting/issue-11515.next.stderr | 14 +++++ .../ui/traits/trait-upcasting/issue-11515.rs | 3 +- tests/ui/traits/trait-upcasting/lifetime.rs | 2 + ...egions.rs => migrate-lint-deny-regions.rs} | 5 +- .../migrate-lint-deny-regions.stderr | 19 +++++++ .../{deref-lint.rs => migrate-lint-deny.rs} | 5 +- .../trait-upcasting/migrate-lint-deny.stderr | 19 +++++++ .../migrate-lint-different-substs.rs | 1 + .../migrate-lint-different-substs.stderr | 5 +- .../multiple-occurrence-ambiguousity.rs | 1 + .../multiple-occurrence-ambiguousity.stderr | 2 +- .../traits/trait-upcasting/normalization.rs | 2 + .../ui/traits/trait-upcasting/replace-vptr.rs | 2 + tests/ui/traits/trait-upcasting/struct.rs | 2 + .../traits/trait-upcasting/subtrait-method.rs | 2 + .../trait-upcasting/subtrait-method.stderr | 20 ++++---- .../type-checking-test-1.current.stderr | 2 +- .../type-checking-test-1.next.stderr | 2 +- .../trait-upcasting/type-checking-test-1.rs | 2 + .../trait-upcasting/type-checking-test-2.rs | 2 + .../type-checking-test-2.stderr | 4 +- .../trait-upcasting/type-checking-test-3.rs | 2 + .../type-checking-test-3.stderr | 4 +- .../trait-upcasting/type-checking-test-4.rs | 2 + .../type-checking-test-4.stderr | 12 ++--- .../upcast-through-struct-tail.current.stderr | 14 +++++ .../upcast-through-struct-tail.next.stderr | 14 +++++ .../upcast-through-struct-tail.rs | 2 +- 71 files changed, 358 insertions(+), 102 deletions(-) create mode 100644 src/doc/unstable-book/src/language-features/trait-upcasting.md create mode 100644 tests/ui/feature-gates/feature-gate-trait_upcasting.rs create mode 100644 tests/ui/feature-gates/feature-gate-trait_upcasting.stderr delete mode 100644 tests/ui/traits/trait-upcasting/deref-lint-regions.stderr delete mode 100644 tests/ui/traits/trait-upcasting/deref-lint.stderr create mode 100644 tests/ui/traits/trait-upcasting/issue-11515.current.stderr create mode 100644 tests/ui/traits/trait-upcasting/issue-11515.next.stderr rename tests/ui/traits/trait-upcasting/{deref-lint-regions.rs => migrate-lint-deny-regions.rs} (52%) create mode 100644 tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.stderr rename tests/ui/traits/trait-upcasting/{deref-lint.rs => migrate-lint-deny.rs} (58%) create mode 100644 tests/ui/traits/trait-upcasting/migrate-lint-deny.stderr create mode 100644 tests/ui/traits/trait-upcasting/upcast-through-struct-tail.current.stderr create mode 100644 tests/ui/traits/trait-upcasting/upcast-through-struct-tail.next.stderr diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 6e3996b45099e..1155366db85e3 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -339,9 +339,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 371b651f5e857..6eed2178ead8d 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -584,6 +584,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 e9d373119fa4d..858faf161f6e8 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -625,6 +625,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 @@ -692,6 +693,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; } @@ -702,6 +710,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, + 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, 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 a9996e4a155bf..b5798af75536d 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -35,6 +35,7 @@ #![feature(iter_intersperse)] #![feature(iter_order_by)] #![feature(let_chains)] +#![cfg_attr(not(bootstrap), feature(trait_upcasting))] #![feature(min_specialization)] #![feature(never_type)] #![feature(rustc_attrs)] diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 65d47b9acc204..94ecc7d95877b 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -532,7 +532,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 3475e582a8f22..dec3419819ff7 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -49,6 +49,7 @@ #![feature(associated_type_bounds)] #![feature(rustc_attrs)] #![feature(control_flow_enum)] +#![cfg_attr(not(bootstrap), 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 342b12ba49848..12aea88e9b6a2 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 13fb97fdc7f3e..89d2b5ef09383 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -113,6 +113,7 @@ #![feature(slice_flatten)] #![feature(error_generic_member_access)] #![feature(error_in_core)] +#![cfg_attr(not(bootstrap), 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 80a47c852692c..b0b6d9943663f 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -10,7 +10,7 @@ #![feature(nonzero_ops)] #![feature(let_chains)] #![feature(lint_reasons)] -#![feature(int_roundings)] +#![cfg_attr(not(bootstrap), 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 75b512f6f729a..8d6da0733fe17 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..6fd277ae8cc3e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-trait_upcasting.stderr @@ -0,0 +1,14 @@ +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: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = 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..ce799dcb7ef65 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/issue-11515.current.stderr @@ -0,0 +1,14 @@ +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: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = 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..ce799dcb7ef65 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/issue-11515.next.stderr @@ -0,0 +1,14 @@ +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: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = 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..86de78f858c9e --- /dev/null +++ b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.current.stderr @@ -0,0 +1,14 @@ +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: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = 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..86de78f858c9e --- /dev/null +++ b/tests/ui/traits/trait-upcasting/upcast-through-struct-tail.next.stderr @@ -0,0 +1,14 @@ +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: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = 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() {} From 483382b93ef6bc0945fe994f8eabeea3381e9ced Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 22 Jan 2024 12:27:43 +0000 Subject: [PATCH 10/13] Add regression test --- tests/ui/traits/upcast_soundness_bug.rs | 69 +++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 tests/ui/traits/upcast_soundness_bug.rs 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); +} From f88e64343e4f9c9ec40c5e7c2c0bcd27ff6052bd Mon Sep 17 00:00:00 2001 From: joboet Date: Thu, 18 Jan 2024 20:33:29 +0100 Subject: [PATCH 11/13] std: move cmath into `sys` --- .../src/sys/{pal/unix/cmath.rs => cmath/builtins.rs} | 2 -- library/std/src/sys/cmath/mod.rs | 11 +++++++++++ .../sys/{pal/windows/cmath.rs => cmath/windows.rs} | 2 -- library/std/src/sys/mod.rs | 4 +++- library/std/src/sys/pal/hermit/mod.rs | 2 -- library/std/src/sys/pal/sgx/mod.rs | 2 -- library/std/src/sys/pal/solid/mod.rs | 2 -- library/std/src/sys/pal/teeos/mod.rs | 2 -- library/std/src/sys/pal/uefi/mod.rs | 2 -- library/std/src/sys/pal/unix/mod.rs | 2 -- library/std/src/sys/pal/unsupported/mod.rs | 2 -- library/std/src/sys/pal/wasi/mod.rs | 2 -- library/std/src/sys/pal/wasm/mod.rs | 2 -- library/std/src/sys/pal/windows/mod.rs | 1 - library/std/src/sys/pal/xous/mod.rs | 2 -- 15 files changed, 14 insertions(+), 26 deletions(-) rename library/std/src/sys/{pal/unix/cmath.rs => cmath/builtins.rs} (98%) create mode 100644 library/std/src/sys/cmath/mod.rs rename library/std/src/sys/{pal/windows/cmath.rs => cmath/windows.rs} (99%) diff --git a/library/std/src/sys/pal/unix/cmath.rs b/library/std/src/sys/cmath/builtins.rs similarity index 98% rename from library/std/src/sys/pal/unix/cmath.rs rename to library/std/src/sys/cmath/builtins.rs index 5346d229116f7..c680132efa4ba 100644 --- a/library/std/src/sys/pal/unix/cmath.rs +++ b/library/std/src/sys/cmath/builtins.rs @@ -1,5 +1,3 @@ -#![cfg(not(test))] - // These symbols are all defined by `libm`, // or by `compiler-builtins` on unsupported platforms. diff --git a/library/std/src/sys/cmath/mod.rs b/library/std/src/sys/cmath/mod.rs new file mode 100644 index 0000000000000..79d5021dd8dc3 --- /dev/null +++ b/library/std/src/sys/cmath/mod.rs @@ -0,0 +1,11 @@ +#![cfg(not(test))] + +cfg_if::cfg_if! { + if #[cfg(target_os = "windows")] { + mod windows; + pub use windows::*; + } else { + mod builtins; + pub use builtins::*; + } +} diff --git a/library/std/src/sys/pal/windows/cmath.rs b/library/std/src/sys/cmath/windows.rs similarity index 99% rename from library/std/src/sys/pal/windows/cmath.rs rename to library/std/src/sys/cmath/windows.rs index 36578d5a34e14..712097f06ff30 100644 --- a/library/std/src/sys/pal/windows/cmath.rs +++ b/library/std/src/sys/cmath/windows.rs @@ -1,5 +1,3 @@ -#![cfg(not(test))] - use core::ffi::{c_double, c_float, c_int}; extern "C" { diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index d95c0d8d0628c..e03e98b18d29f 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -3,9 +3,11 @@ /// descriptors. mod pal; -pub mod os_str; mod personality; +pub mod cmath; +pub mod os_str; + // FIXME(117276): remove this, move feature implementations into individual // submodules. pub use pal::*; diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index 5033629691960..3c83afa280be5 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -19,8 +19,6 @@ use crate::os::raw::c_char; pub mod alloc; pub mod args; -#[path = "../unix/cmath.rs"] -pub mod cmath; pub mod env; pub mod fd; pub mod fs; diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs index 893c5f765a797..a769fc1ef5932 100644 --- a/library/std/src/sys/pal/sgx/mod.rs +++ b/library/std/src/sys/pal/sgx/mod.rs @@ -13,8 +13,6 @@ mod waitqueue; pub mod alloc; pub mod args; -#[path = "../unix/cmath.rs"] -pub mod cmath; pub mod env; pub mod fd; #[path = "../unsupported/fs.rs"] diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs index 5742ce9d72c69..46699e64169f5 100644 --- a/library/std/src/sys/pal/solid/mod.rs +++ b/library/std/src/sys/pal/solid/mod.rs @@ -21,8 +21,6 @@ mod itron { pub mod alloc; #[path = "../unsupported/args.rs"] pub mod args; -#[path = "../unix/cmath.rs"] -pub mod cmath; pub mod env; // `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as // `crate::sys::error` diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs index 764a4e6ad35ea..95a5b97ea4237 100644 --- a/library/std/src/sys/pal/teeos/mod.rs +++ b/library/std/src/sys/pal/teeos/mod.rs @@ -11,8 +11,6 @@ pub use self::rand::hashmap_random_keys; pub mod alloc; #[path = "../unsupported/args.rs"] pub mod args; -#[path = "../unix/cmath.rs"] -pub mod cmath; #[path = "../unsupported/env.rs"] pub mod env; pub mod locks; diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs index fb1a531182a7f..9ee753aa1a0c1 100644 --- a/library/std/src/sys/pal/uefi/mod.rs +++ b/library/std/src/sys/pal/uefi/mod.rs @@ -14,8 +14,6 @@ pub mod alloc; pub mod args; -#[path = "../unix/cmath.rs"] -pub mod cmath; pub mod env; #[path = "../unsupported/fs.rs"] pub mod fs; diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index 86027c2b0b0af..43cb9d89be9dd 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -11,8 +11,6 @@ pub mod weak; pub mod alloc; pub mod android; pub mod args; -#[path = "../unix/cmath.rs"] -pub mod cmath; pub mod env; pub mod fd; pub mod fs; diff --git a/library/std/src/sys/pal/unsupported/mod.rs b/library/std/src/sys/pal/unsupported/mod.rs index 6254c67a2a3b2..b56ded8579c4d 100644 --- a/library/std/src/sys/pal/unsupported/mod.rs +++ b/library/std/src/sys/pal/unsupported/mod.rs @@ -2,8 +2,6 @@ pub mod alloc; pub mod args; -#[path = "../unix/cmath.rs"] -pub mod cmath; pub mod env; pub mod fs; pub mod io; diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasi/mod.rs index c1fc053bf049a..4ffc8ecdd67ee 100644 --- a/library/std/src/sys/pal/wasi/mod.rs +++ b/library/std/src/sys/pal/wasi/mod.rs @@ -20,8 +20,6 @@ use crate::mem; #[path = "../unix/alloc.rs"] pub mod alloc; pub mod args; -#[path = "../unix/cmath.rs"] -pub mod cmath; pub mod env; pub mod fd; pub mod fs; diff --git a/library/std/src/sys/pal/wasm/mod.rs b/library/std/src/sys/pal/wasm/mod.rs index d2181565887ff..76306b618d82b 100644 --- a/library/std/src/sys/pal/wasm/mod.rs +++ b/library/std/src/sys/pal/wasm/mod.rs @@ -19,8 +19,6 @@ pub mod alloc; #[path = "../unsupported/args.rs"] pub mod args; -#[path = "../unix/cmath.rs"] -pub mod cmath; pub mod env; #[path = "../unsupported/fs.rs"] pub mod fs; diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index d097a7b8bb265..364521dba40ac 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -15,7 +15,6 @@ pub mod compat; pub mod alloc; pub mod args; pub mod c; -pub mod cmath; pub mod env; pub mod fs; pub mod handle; diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs index 230067907c8f0..fba5e273babe8 100644 --- a/library/std/src/sys/pal/xous/mod.rs +++ b/library/std/src/sys/pal/xous/mod.rs @@ -3,8 +3,6 @@ pub mod alloc; #[path = "../unsupported/args.rs"] pub mod args; -#[path = "../unix/cmath.rs"] -pub mod cmath; #[path = "../unsupported/env.rs"] pub mod env; #[path = "../unsupported/fs.rs"] From c5a4e074f052d0528451035df58c0f612ee45118 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 22 Jan 2024 16:14:17 +0100 Subject: [PATCH 12/13] Use `-> !` to test divergence --- tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs b/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs index 6f4b81b9b25b0..57151e246ff56 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs +++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs @@ -9,21 +9,24 @@ enum Void {} // A never pattern alone diverges. -fn never_arg(!: Void) -> u32 {} +fn never_arg(!: Void) -> ! {} -fn ref_never_arg(&!: &Void) -> u32 {} +fn never_arg_returns_anything(!: Void) -> T {} -fn never_let() -> u32 { +fn ref_never_arg(&!: &Void) -> ! {} + +fn never_let() -> ! { let ptr: *const Void = std::ptr::null(); unsafe { let ! = *ptr; } } -fn never_match() -> u32 { +fn never_match() -> ! { let ptr: *const Void = std::ptr::null(); unsafe { match *ptr { ! }; } - println!(); // Ensures this typechecks because of divergence. + // Ensures this typechecks because of divergence and not the type of the match expression. + println!(); } From 3ff10242fee5356cb4be91db6df2eee6b9a34089 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 18 Jan 2024 21:14:16 +0100 Subject: [PATCH 13/13] Test async fn --- .../120240-async-fn-never-arg.rs | 16 ++++++++++++++++ .../120240-async-fn-never-arg.stderr | 12 ++++++++++++ .../ui/rfcs/rfc-0000-never_patterns/diverges.rs | 6 ++++++ 3 files changed, 34 insertions(+) create mode 100644 tests/ui/rfcs/rfc-0000-never_patterns/120240-async-fn-never-arg.rs create mode 100644 tests/ui/rfcs/rfc-0000-never_patterns/120240-async-fn-never-arg.stderr diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/120240-async-fn-never-arg.rs b/tests/ui/rfcs/rfc-0000-never_patterns/120240-async-fn-never-arg.rs new file mode 100644 index 0000000000000..9150c831c8960 --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/120240-async-fn-never-arg.rs @@ -0,0 +1,16 @@ +// edition: 2018 +// known-bug: #120240 +#![feature(never_patterns)] +#![allow(incomplete_features)] + +fn main() {} + +enum Void {} + +// Divergence is not detected. +async fn async_never(!: Void) -> ! {} // gives an error + +// Divergence is detected +async fn async_let(x: Void) -> ! { + let ! = x; +} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/120240-async-fn-never-arg.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/120240-async-fn-never-arg.stderr new file mode 100644 index 0000000000000..fa71feee5f5aa --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/120240-async-fn-never-arg.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/120240-async-fn-never-arg.rs:11:36 + | +LL | async fn async_never(!: Void) -> ! {} // gives an error + | ^^ expected `!`, found `()` + | + = note: expected type `!` + found unit type `()` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs b/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs index 57151e246ff56..3783100b50282 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs +++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs @@ -1,4 +1,5 @@ // check-pass +// edition: 2018 #![feature(never_patterns)] #![allow(incomplete_features)] #![deny(unreachable_patterns)] @@ -30,3 +31,8 @@ fn never_match() -> ! { // Ensures this typechecks because of divergence and not the type of the match expression. println!(); } + +// Note: divergence is not detected for async fns when the `!` is in the argument (#120240). +async fn async_let(x: Void) -> ! { + let ! = x; +}