Skip to content

Commit 9c06e1b

Browse files
committed
Auto merge of #95448 - Dylan-DPC:rollup-wpj5yto, r=Dylan-DPC
Rollup of 4 pull requests Successful merges: - #93840 (Stabilize Termination and ExitCode) - #95256 (Ensure io::Error's bitpacked repr doesn't accidentally impl UnwindSafe) - #95386 (Suggest wrapping patterns in enum variants) - #95437 (diagnostics: regression test for derive bounds) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents 5e1d19d + 2471502 commit 9c06e1b

17 files changed

+388
-39
lines changed

compiler/rustc_infer/src/infer/error_reporting/mod.rs

+69
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ use rustc_hir::def_id::DefId;
6565
use rustc_hir::lang_items::LangItem;
6666
use rustc_hir::{Item, ItemKind, Node};
6767
use rustc_middle::dep_graph::DepContext;
68+
use rustc_middle::ty::print::with_no_trimmed_paths;
6869
use rustc_middle::ty::{
6970
self,
7071
error::TypeError,
@@ -1736,6 +1737,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
17361737
};
17371738

17381739
if should_suggest_fixes {
1740+
self.suggest_tuple_pattern(cause, &exp_found, diag);
17391741
self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
17401742
self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
17411743
self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
@@ -1766,6 +1768,73 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
17661768
self.note_error_origin(diag, cause, exp_found, terr);
17671769
}
17681770

1771+
fn suggest_tuple_pattern(
1772+
&self,
1773+
cause: &ObligationCause<'tcx>,
1774+
exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
1775+
diag: &mut Diagnostic,
1776+
) {
1777+
// Heavily inspired by `FnCtxt::suggest_compatible_variants`, with
1778+
// some modifications due to that being in typeck and this being in infer.
1779+
if let ObligationCauseCode::Pattern { .. } = cause.code() {
1780+
if let ty::Adt(expected_adt, substs) = exp_found.expected.kind() {
1781+
let compatible_variants: Vec<_> = expected_adt
1782+
.variants()
1783+
.iter()
1784+
.filter(|variant| {
1785+
variant.fields.len() == 1 && variant.ctor_kind == hir::def::CtorKind::Fn
1786+
})
1787+
.filter_map(|variant| {
1788+
let sole_field = &variant.fields[0];
1789+
let sole_field_ty = sole_field.ty(self.tcx, substs);
1790+
if same_type_modulo_infer(sole_field_ty, exp_found.found) {
1791+
let variant_path =
1792+
with_no_trimmed_paths!(self.tcx.def_path_str(variant.def_id));
1793+
// FIXME #56861: DRYer prelude filtering
1794+
if let Some(path) = variant_path.strip_prefix("std::prelude::") {
1795+
if let Some((_, path)) = path.split_once("::") {
1796+
return Some(path.to_string());
1797+
}
1798+
}
1799+
Some(variant_path)
1800+
} else {
1801+
None
1802+
}
1803+
})
1804+
.collect();
1805+
match &compatible_variants[..] {
1806+
[] => {}
1807+
[variant] => {
1808+
diag.multipart_suggestion_verbose(
1809+
&format!("try wrapping the pattern in `{}`", variant),
1810+
vec![
1811+
(cause.span.shrink_to_lo(), format!("{}(", variant)),
1812+
(cause.span.shrink_to_hi(), ")".to_string()),
1813+
],
1814+
Applicability::MaybeIncorrect,
1815+
);
1816+
}
1817+
_ => {
1818+
// More than one matching variant.
1819+
diag.multipart_suggestions(
1820+
&format!(
1821+
"try wrapping the pattern in a variant of `{}`",
1822+
self.tcx.def_path_str(expected_adt.did())
1823+
),
1824+
compatible_variants.into_iter().map(|variant| {
1825+
vec![
1826+
(cause.span.shrink_to_lo(), format!("{}(", variant)),
1827+
(cause.span.shrink_to_hi(), ")".to_string()),
1828+
]
1829+
}),
1830+
Applicability::MaybeIncorrect,
1831+
);
1832+
}
1833+
}
1834+
}
1835+
}
1836+
}
1837+
17691838
pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Binder<'tcx, Ty<'tcx>>> {
17701839
if let ty::Opaque(def_id, substs) = ty.kind() {
17711840
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);

compiler/rustc_typeck/src/check/demand.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -268,10 +268,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
268268
expr_ty: Ty<'tcx>,
269269
) {
270270
if let ty::Adt(expected_adt, substs) = expected.kind() {
271-
if !expected_adt.is_enum() {
272-
return;
273-
}
274-
275271
// If the expression is of type () and it's the return expression of a block,
276272
// we suggest adding a separate return expression instead.
277273
// (To avoid things like suggesting `Ok(while .. { .. })`.)
@@ -336,7 +332,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
336332
let compatible_variants: Vec<String> = expected_adt
337333
.variants()
338334
.iter()
339-
.filter(|variant| variant.fields.len() == 1)
335+
.filter(|variant| {
336+
variant.fields.len() == 1 && variant.ctor_kind == hir::def::CtorKind::Fn
337+
})
340338
.filter_map(|variant| {
341339
let sole_field = &variant.fields[0];
342340
let sole_field_ty = sole_field.ty(self.tcx, substs);

library/std/src/io/error/repr_bitpacked.rs

+15-5
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
105105
use super::{Custom, ErrorData, ErrorKind, SimpleMessage};
106106
use alloc::boxed::Box;
107+
use core::marker::PhantomData;
107108
use core::mem::{align_of, size_of};
108109
use core::ptr::NonNull;
109110

@@ -114,8 +115,17 @@ const TAG_CUSTOM: usize = 0b01;
114115
const TAG_OS: usize = 0b10;
115116
const TAG_SIMPLE: usize = 0b11;
116117

118+
/// The internal representation.
119+
///
120+
/// See the module docs for more, this is just a way to hack in a check that we
121+
/// indeed are not unwind-safe.
122+
///
123+
/// ```compile_fail,E0277
124+
/// fn is_unwind_safe<T: core::panic::UnwindSafe>() {}
125+
/// is_unwind_safe::<std::io::Error>();
126+
/// ```
117127
#[repr(transparent)]
118-
pub(super) struct Repr(NonNull<()>);
128+
pub(super) struct Repr(NonNull<()>, PhantomData<ErrorData<Box<Custom>>>);
119129

120130
// All the types `Repr` stores internally are Send + Sync, and so is it.
121131
unsafe impl Send for Repr {}
@@ -145,7 +155,7 @@ impl Repr {
145155
// box, and `TAG_CUSTOM` just... isn't zero -- it's `0b01`). Therefore,
146156
// `TAG_CUSTOM + p` isn't zero and so `tagged` can't be, and the
147157
// `new_unchecked` is safe.
148-
let res = Self(unsafe { NonNull::new_unchecked(tagged) });
158+
let res = Self(unsafe { NonNull::new_unchecked(tagged) }, PhantomData);
149159
// quickly smoke-check we encoded the right thing (This generally will
150160
// only run in libstd's tests, unless the user uses -Zbuild-std)
151161
debug_assert!(matches!(res.data(), ErrorData::Custom(_)), "repr(custom) encoding failed");
@@ -156,7 +166,7 @@ impl Repr {
156166
pub(super) fn new_os(code: i32) -> Self {
157167
let utagged = ((code as usize) << 32) | TAG_OS;
158168
// Safety: `TAG_OS` is not zero, so the result of the `|` is not 0.
159-
let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) });
169+
let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) }, PhantomData);
160170
// quickly smoke-check we encoded the right thing (This generally will
161171
// only run in libstd's tests, unless the user uses -Zbuild-std)
162172
debug_assert!(
@@ -170,7 +180,7 @@ impl Repr {
170180
pub(super) fn new_simple(kind: ErrorKind) -> Self {
171181
let utagged = ((kind as usize) << 32) | TAG_SIMPLE;
172182
// Safety: `TAG_SIMPLE` is not zero, so the result of the `|` is not 0.
173-
let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) });
183+
let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) }, PhantomData);
174184
// quickly smoke-check we encoded the right thing (This generally will
175185
// only run in libstd's tests, unless the user uses -Zbuild-std)
176186
debug_assert!(
@@ -184,7 +194,7 @@ impl Repr {
184194
#[inline]
185195
pub(super) const fn new_simple_message(m: &'static SimpleMessage) -> Self {
186196
// Safety: References are never null.
187-
Self(unsafe { NonNull::new_unchecked(m as *const _ as *mut ()) })
197+
Self(unsafe { NonNull::new_unchecked(m as *const _ as *mut ()) }, PhantomData)
188198
}
189199

190200
#[inline]

library/std/src/process.rs

+68-24
Original file line numberDiff line numberDiff line change
@@ -1417,6 +1417,15 @@ impl From<fs::File> for Stdio {
14171417
/// For proper error reporting of failed processes, print the value of `ExitStatus` or
14181418
/// `ExitStatusError` using their implementations of [`Display`](crate::fmt::Display).
14191419
///
1420+
/// # Differences from `ExitStatus`
1421+
///
1422+
/// `ExitCode` is intended for terminating the currently running process, via
1423+
/// the `Termination` trait, in contrast to [`ExitStatus`], which represents the
1424+
/// termination of a child process. These APIs are separate due to platform
1425+
/// compatibility differences and their expected usage; it is not generally
1426+
/// possible to exactly reproduce an ExitStatus from a child for the current
1427+
/// process after the fact.
1428+
///
14201429
/// [`status`]: Command::status
14211430
/// [`wait`]: Child::wait
14221431
//
@@ -1649,8 +1658,16 @@ impl fmt::Display for ExitStatusError {
16491658
#[unstable(feature = "exit_status_error", issue = "84908")]
16501659
impl crate::error::Error for ExitStatusError {}
16511660

1652-
/// This type represents the status code a process can return to its
1653-
/// parent under normal termination.
1661+
/// This type represents the status code the current process can return
1662+
/// to its parent under normal termination.
1663+
///
1664+
/// `ExitCode` is intended to be consumed only by the standard library (via
1665+
/// [`Termination::report()`]), and intentionally does not provide accessors like
1666+
/// `PartialEq`, `Eq`, or `Hash`. Instead the standard library provides the
1667+
/// canonical `SUCCESS` and `FAILURE` exit codes as well as `From<u8> for
1668+
/// ExitCode` for constructing other arbitrary exit codes.
1669+
///
1670+
/// # Portability
16541671
///
16551672
/// Numeric values used in this type don't have portable meanings, and
16561673
/// different platforms may mask different amounts of them.
@@ -1661,52 +1678,78 @@ impl crate::error::Error for ExitStatusError {}
16611678
/// [`SUCCESS`]: ExitCode::SUCCESS
16621679
/// [`FAILURE`]: ExitCode::FAILURE
16631680
///
1664-
/// **Warning**: While various forms of this were discussed in [RFC #1937],
1665-
/// it was ultimately cut from that RFC, and thus this type is more subject
1666-
/// to change even than the usual unstable item churn.
1681+
/// # Differences from `ExitStatus`
1682+
///
1683+
/// `ExitCode` is intended for terminating the currently running process, via
1684+
/// the `Termination` trait, in contrast to [`ExitStatus`], which represents the
1685+
/// termination of a child process. These APIs are separate due to platform
1686+
/// compatibility differences and their expected usage; it is not generally
1687+
/// possible to exactly reproduce an ExitStatus from a child for the current
1688+
/// process after the fact.
1689+
///
1690+
/// # Examples
1691+
///
1692+
/// `ExitCode` can be returned from the `main` function of a crate, as it implements
1693+
/// [`Termination`]:
1694+
///
1695+
/// ```
1696+
/// use std::process::ExitCode;
1697+
/// # fn check_foo() -> bool { true }
16671698
///
1668-
/// [RFC #1937]: https://github.com/rust-lang/rfcs/pull/1937
1699+
/// fn main() -> ExitCode {
1700+
/// if !check_foo() {
1701+
/// return ExitCode::from(42);
1702+
/// }
1703+
///
1704+
/// ExitCode::SUCCESS
1705+
/// }
1706+
/// ```
16691707
#[derive(Clone, Copy, Debug)]
1670-
#[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
1708+
#[stable(feature = "process_exitcode", since = "1.60.0")]
16711709
pub struct ExitCode(imp::ExitCode);
16721710

1673-
#[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
1711+
#[stable(feature = "process_exitcode", since = "1.60.0")]
16741712
impl ExitCode {
1675-
/// The canonical ExitCode for successful termination on this platform.
1713+
/// The canonical `ExitCode` for successful termination on this platform.
16761714
///
16771715
/// Note that a `()`-returning `main` implicitly results in a successful
16781716
/// termination, so there's no need to return this from `main` unless
16791717
/// you're also returning other possible codes.
1680-
#[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
1718+
#[stable(feature = "process_exitcode", since = "1.60.0")]
16811719
pub const SUCCESS: ExitCode = ExitCode(imp::ExitCode::SUCCESS);
16821720

1683-
/// The canonical ExitCode for unsuccessful termination on this platform.
1721+
/// The canonical `ExitCode` for unsuccessful termination on this platform.
16841722
///
16851723
/// If you're only returning this and `SUCCESS` from `main`, consider
16861724
/// instead returning `Err(_)` and `Ok(())` respectively, which will
16871725
/// return the same codes (but will also `eprintln!` the error).
1688-
#[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
1726+
#[stable(feature = "process_exitcode", since = "1.60.0")]
16891727
pub const FAILURE: ExitCode = ExitCode(imp::ExitCode::FAILURE);
16901728
}
16911729

16921730
impl ExitCode {
1693-
// This should not be stabilized when stabilizing ExitCode, we don't know that i32 will serve
1731+
// This is private/perma-unstable because ExitCode is opaque; we don't know that i32 will serve
16941732
// all usecases, for example windows seems to use u32, unix uses the 8-15th bits of an i32, we
16951733
// likely want to isolate users anything that could restrict the platform specific
16961734
// representation of an ExitCode
16971735
//
16981736
// More info: https://internals.rust-lang.org/t/mini-pre-rfc-redesigning-process-exitstatus/5426
1699-
/// Convert an ExitCode into an i32
1700-
#[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
1737+
/// Convert an `ExitCode` into an i32
1738+
#[unstable(
1739+
feature = "process_exitcode_internals",
1740+
reason = "exposed only for libstd",
1741+
issue = "none"
1742+
)]
17011743
#[inline]
1744+
#[doc(hidden)]
17021745
pub fn to_i32(self) -> i32 {
17031746
self.0.as_i32()
17041747
}
17051748
}
17061749

1707-
#[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
1750+
#[stable(feature = "process_exitcode", since = "1.60.0")]
17081751
impl From<u8> for ExitCode {
1709-
/// Construct an exit code from an arbitrary u8 value.
1752+
/// Construct an `ExitCode` from an arbitrary u8 value.
17101753
fn from(code: u8) -> Self {
17111754
ExitCode(imp::ExitCode::from(code))
17121755
}
@@ -2049,26 +2092,27 @@ pub fn id() -> u32 {
20492092
/// standard library's runtime for convenience. Other runtimes are not required
20502093
/// to provide similar functionality.
20512094
#[cfg_attr(not(test), lang = "termination")]
2052-
#[unstable(feature = "termination_trait_lib", issue = "43301")]
2095+
#[stable(feature = "termination_trait_lib", since = "1.60.0")]
20532096
#[rustc_on_unimplemented(
20542097
message = "`main` has invalid return type `{Self}`",
20552098
label = "`main` can only return types that implement `{Termination}`"
20562099
)]
20572100
pub trait Termination {
20582101
/// Is called to get the representation of the value as status code.
20592102
/// This status code is returned to the operating system.
2103+
#[stable(feature = "termination_trait_lib", since = "1.60.0")]
20602104
fn report(self) -> ExitCode;
20612105
}
20622106

2063-
#[unstable(feature = "termination_trait_lib", issue = "43301")]
2107+
#[stable(feature = "termination_trait_lib", since = "1.60.0")]
20642108
impl Termination for () {
20652109
#[inline]
20662110
fn report(self) -> ExitCode {
20672111
ExitCode::SUCCESS.report()
20682112
}
20692113
}
20702114

2071-
#[unstable(feature = "termination_trait_lib", issue = "43301")]
2115+
#[stable(feature = "termination_trait_lib", since = "1.60.0")]
20722116
impl<E: fmt::Debug> Termination for Result<(), E> {
20732117
fn report(self) -> ExitCode {
20742118
match self {
@@ -2078,14 +2122,14 @@ impl<E: fmt::Debug> Termination for Result<(), E> {
20782122
}
20792123
}
20802124

2081-
#[unstable(feature = "termination_trait_lib", issue = "43301")]
2125+
#[stable(feature = "termination_trait_lib", since = "1.60.0")]
20822126
impl Termination for ! {
20832127
fn report(self) -> ExitCode {
20842128
self
20852129
}
20862130
}
20872131

2088-
#[unstable(feature = "termination_trait_lib", issue = "43301")]
2132+
#[stable(feature = "termination_trait_lib", since = "1.60.0")]
20892133
impl<E: fmt::Debug> Termination for Result<!, E> {
20902134
fn report(self) -> ExitCode {
20912135
let Err(err) = self;
@@ -2094,15 +2138,15 @@ impl<E: fmt::Debug> Termination for Result<!, E> {
20942138
}
20952139
}
20962140

2097-
#[unstable(feature = "termination_trait_lib", issue = "43301")]
2141+
#[stable(feature = "termination_trait_lib", since = "1.60.0")]
20982142
impl<E: fmt::Debug> Termination for Result<Infallible, E> {
20992143
fn report(self) -> ExitCode {
21002144
let Err(err) = self;
21012145
Err::<!, _>(err).report()
21022146
}
21032147
}
21042148

2105-
#[unstable(feature = "termination_trait_lib", issue = "43301")]
2149+
#[stable(feature = "termination_trait_lib", since = "1.60.0")]
21062150
impl Termination for ExitCode {
21072151
#[inline]
21082152
fn report(self) -> ExitCode {

library/test/src/lib.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@
1919
#![feature(bench_black_box)]
2020
#![feature(internal_output_capture)]
2121
#![feature(staged_api)]
22-
#![feature(termination_trait_lib)]
23-
#![feature(process_exitcode_placeholder)]
22+
#![feature(process_exitcode_internals)]
2423
#![feature(test)]
2524
#![feature(total_cmp)]
2625

0 commit comments

Comments
 (0)