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 1cc1f11b3c8..85d10872b3d 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 dd41cb5a61f..b6c3c34078f 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 44795022cba..bebeecebbb6 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 81d5304b812..e5e31f7caaa 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 e58c9068af8..6faded76a4a 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 555c822ad6d..2d4963a8b90 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 1337ade62c0..486b6d4bf2e 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 e17e6feae07..7a4c33d36e4 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 4028de27cae..a06f4c6ba12 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 ca83e2be5c1..87e89a464bc 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 649826d25ce..b73d9f3ff4c 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 aca17ec77a4..4167c417d83 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 c887368b2a2..4d9f5b831c1 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 4167c417d83..3be37d1a3be 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 e6c2091d85a..f65e9b698ab 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 00000000000..5c852c8adcc --- /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 00000000000..c9cd3f53944 --- /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 00000000000..6b85ada3aad --- /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 00000000000..08a1bbe9bff --- /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 00000000000..40aa2bd29e5 --- /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 ddb4224b60d..136ed1a709e 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 5c852c8adcc..f7e4007b920 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 c9cd3f53944..c33a5855d50 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 40aa2bd29e5..6f4b81b9b25 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 | 40 +++++++-------- .../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, 368 insertions(+), 112 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 6e3996b4509..1155366db85 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 371b651f5e8..6eed2178ead 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 e9d373119fa..858faf161f6 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 98bafc0f263..4673b801dc1 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 a9996e4a155..b5798af7553 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 65d47b9acc2..94ecc7d9587 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 3475e582a8f..dec3419819f 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 342b12ba498..12aea88e9b6 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 13fb97fdc7f..89d2b5ef093 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 00000000000..3697ae38f9d --- /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 80a47c85269..b0b6d994366 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 7d46ecd8f6e..648ac07c43e 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 75b512f6f72..8d6da0733fe 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 ddaefeca3a3..8432012a9ba 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 9e203fba113..b223aff4e94 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 0201c889706..a4eb669e321 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 7e2cf661369..1f7bfb1d5bd 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 7748cdda943..c667ac143a3 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 bdf77da713a..adef9525bf1 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 00000000000..e4102f1cfa7 --- /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 00000000000..6fd277ae8cc --- /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 6ca82d1b872..08bb0cf42e8 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 2a482f74668..8e0378e94f0 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 5e4d958c895..5b4f6d4be0c 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 927a9d6b94f..4a5e445d1ef 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 1a410519a4e..99c82b88d9c 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 538cd8329cc..570ec5160bf 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 4a379d9f875..eae5cf8d58d 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 557a4420a3d..00000000000 --- 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 5a13659edf5..00000000000 --- 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 366eae1a58a..e4784fa4101 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 193d09e3501..fa93e28c73b 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 9a78339a4ec..a4f81c464b4 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 e7ca6fa5208..58e72d9d7ef 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 119b3109c63..1538e2f3fd7 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 119b3109c63..1538e2f3fd7 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 5a493fd48b3..ffed8beb448 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 999f3b16f50..79fb643eacd 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 fcc80c6148f..6b6a26d1593 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 9269a5e3e9f..e634bbd5ac6 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 e70b99d28c7..3aa21ee3ddd 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 77ce627078f..b672963ae98 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 00000000000..ce799dcb7ef --- /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 00000000000..ce799dcb7ef --- /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 a1edb53ec37..31ea2fb353c 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 6c65c38870f..9825158c2dd 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 946305cbb2b..da1a9cc2775 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 00000000000..a5f3660d4bc --- /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 68838d2ae20..926b3649e01 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 00000000000..29997a9b3d9 --- /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 2c9126c863d..8a90a09ff04 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 a447f9cf83b..6245da5a176 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 0e17c276717..2e53a00a90e 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 c888ccc1ebb..70ba1fcaf38 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 b594969483a..24da1ec5dfb 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 4a7304ec2d7..9ccfc9306ac 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 64fa9ca1b5f..a3e41696956 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 20277280440..136d15af0e8 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 3fdf3f48161..918159e845b 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 - | -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 - | -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 | +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: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: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 47ffa68b8ff..10c22440a83 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 47ffa68b8ff..10c22440a83 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 7d3deeeaa61..54c3c5e0c28 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 b4df0f5a902..b024b27750b 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 f84ea93dc67..3e59b9d3363 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 3685569d98d..b2db3a12797 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 640a6066268..e6cb6a75399 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 65391502386..f40c48f0d12 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 7e7548955d3..8d506e5807e 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 00000000000..86de78f858c --- /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 00000000000..86de78f858c --- /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 f8cf793e4a4..948f058e528 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 00000000000..32e32850925 --- /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 5346d229116..c680132efa4 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 00000000000..79d5021dd8d --- /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 36578d5a34e..712097f06ff 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 d95c0d8d062..e03e98b18d2 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 50336296919..3c83afa280b 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 893c5f765a7..a769fc1ef59 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 5742ce9d72c..46699e64169 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 764a4e6ad35..95a5b97ea42 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 fb1a531182a..9ee753aa1a0 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 86027c2b0b0..43cb9d89be9 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 6254c67a2a3..b56ded8579c 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 c1fc053bf04..4ffc8ecdd67 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 d2181565887..76306b618d8 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 d097a7b8bb2..364521dba40 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 230067907c8..fba5e273bab 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 6f4b81b9b25..57151e246ff 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 00000000000..9150c831c89 --- /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 00000000000..fa71feee5f5 --- /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 57151e246ff..3783100b502 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; +}