Auto merge of #150500 - jhpratt:rollup-ei77kqi, r=jhpratt

Rollup of 3 pull requests

Successful merges:

 - rust-lang/rust#146792 (Implement `TryFrom<char>` for `usize`.)
 - rust-lang/rust#150484 (Mark set_times as unavailable for RTEMS target)
 - rust-lang/rust#150498 (mir_build: Remove several remnants of `#![feature(inline_const_pat)]`)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-12-30 08:02:56 +00:00
commit d465f99043
7 changed files with 93 additions and 50 deletions

View file

@ -832,18 +832,18 @@ pub enum PatKind<'tcx> {
value: ty::Value<'tcx>,
},
/// Pattern obtained by converting a constant (inline or named) to its pattern
/// representation using `const_to_pat`. This is used for unsafety checking.
/// Wrapper node representing a named constant that was lowered to a pattern
/// using `const_to_pat`.
///
/// This is used by some diagnostics for non-exhaustive matches, to map
/// the pattern node back to the `DefId` of its original constant.
///
/// FIXME(#150498): Can we make this an `Option<DefId>` field on `Pat`
/// instead, so that non-diagnostic code can ignore it more easily?
ExpandedConstant {
/// [DefId] of the constant item.
def_id: DefId,
/// The pattern that the constant lowered to.
///
/// HACK: we need to keep the `DefId` of inline constants around for unsafety checking;
/// therefore when a range pattern contains inline constants, we re-wrap the range pattern
/// with the `ExpandedConstant` nodes that correspond to the range endpoints. Hence
/// `subpattern` may actually be a range pattern, and `def_id` be the constant for one of
/// its endpoints.
subpattern: Box<Pat<'tcx>>,
},

View file

@ -410,14 +410,6 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
visit::walk_pat(self, pat);
self.inside_adt = old_inside_adt;
}
PatKind::ExpandedConstant { def_id, .. } => {
if let Some(def) = def_id.as_local()
&& matches!(self.tcx.def_kind(def_id), DefKind::InlineConst)
{
self.visit_inner_body(def);
}
visit::walk_pat(self, pat);
}
_ => {
visit::walk_pat(self, pat);
}

View file

@ -5,7 +5,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::codes::*;
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, struct_span_code_err};
use rustc_hir::def::*;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{self as hir, BindingMode, ByRef, HirId, MatchSource};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::Level;
@ -687,12 +687,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
unpeeled_pat = subpattern;
}
if let PatKind::ExpandedConstant { def_id, .. } = unpeeled_pat.kind
&& let DefKind::Const = self.tcx.def_kind(def_id)
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span)
// We filter out paths with multiple path::segments.
&& snippet.chars().all(|c| c.is_alphanumeric() || c == '_')
{
if let Some(def_id) = is_const_pat_that_looks_like_binding(self.tcx, unpeeled_pat) {
let span = self.tcx.def_span(def_id);
let variable = self.tcx.item_name(def_id).to_string();
// When we encounter a constant as the binding name, point at the `const` definition.
@ -1209,6 +1204,26 @@ fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool {
}
}
/// If the given pattern is a named constant that looks like it could have been
/// intended to be a binding, returns the `DefId` of the named constant.
///
/// Diagnostics use this to give more detailed suggestions for non-exhaustive
/// matches.
fn is_const_pat_that_looks_like_binding<'tcx>(tcx: TyCtxt<'tcx>, pat: &Pat<'tcx>) -> Option<DefId> {
// The pattern must be a named constant, and the name that appears in
// the pattern's source text must resemble a plain identifier without any
// `::` namespace separators or other non-identifier characters.
if let PatKind::ExpandedConstant { def_id, .. } = pat.kind
&& matches!(tcx.def_kind(def_id), DefKind::Const)
&& let Ok(snippet) = tcx.sess.source_map().span_to_snippet(pat.span)
&& snippet.chars().all(|c| c.is_alphanumeric() || c == '_')
{
Some(def_id)
} else {
None
}
}
/// Report that a match is not exhaustive.
fn report_non_exhaustive_match<'p, 'tcx>(
cx: &PatCtxt<'p, 'tcx>,
@ -1303,12 +1318,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
for &arm in arms {
let arm = &thir.arms[arm];
if let PatKind::ExpandedConstant { def_id, .. } = arm.pattern.kind
&& !matches!(cx.tcx.def_kind(def_id), DefKind::InlineConst)
&& let Ok(snippet) = cx.tcx.sess.source_map().span_to_snippet(arm.pattern.span)
// We filter out paths with multiple path::segments.
&& snippet.chars().all(|c| c.is_alphanumeric() || c == '_')
{
if let Some(def_id) = is_const_pat_that_looks_like_binding(cx.tcx, &arm.pattern) {
let const_name = cx.tcx.item_name(def_id);
err.span_label(
arm.pattern.span,

View file

@ -187,7 +187,7 @@ impl<'tcx> ConstToPat<'tcx> {
}
// Wrap the pattern in a marker node to indicate that it is the result of lowering a
// constant. This is used for diagnostics, and for unsafety checking of inline const blocks.
// constant. This is used for diagnostics.
let kind = PatKind::ExpandedConstant { subpattern: inlined_const_as_pat, def_id: uv.def };
Box::new(Pat { kind, ty, span: self.span })
}

View file

@ -21,7 +21,6 @@ use rustc_middle::ty::adjustment::{PatAdjust, PatAdjustment};
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_span::def_id::DefId;
use rustc_span::{ErrorGuaranteed, Span};
use tracing::{debug, instrument};
@ -131,9 +130,8 @@ impl<'tcx> PatCtxt<'tcx> {
fn lower_pattern_range_endpoint(
&mut self,
expr: Option<&'tcx hir::PatExpr<'tcx>>,
// Out-parameters collecting extra data to be reapplied by the caller
// Out-parameter collecting extra data to be reapplied by the caller
ascriptions: &mut Vec<Ascription<'tcx>>,
expanded_consts: &mut Vec<DefId>,
) -> Result<Option<PatRangeBoundary<'tcx>>, ErrorGuaranteed> {
let Some(expr) = expr else { return Ok(None) };
@ -148,8 +146,10 @@ impl<'tcx> PatCtxt<'tcx> {
ascriptions.push(ascription);
kind = subpattern.kind;
}
PatKind::ExpandedConstant { def_id, subpattern } => {
expanded_consts.push(def_id);
PatKind::ExpandedConstant { def_id: _, subpattern } => {
// Expanded-constant nodes are currently only needed by
// diagnostics that don't apply to range patterns, so we
// can just discard them here.
kind = subpattern.kind;
}
_ => break,
@ -227,10 +227,7 @@ impl<'tcx> PatCtxt<'tcx> {
// Collect extra data while lowering the endpoints, to be reapplied later.
let mut ascriptions = vec![];
let mut expanded_consts = vec![];
let mut lower_endpoint =
|expr| self.lower_pattern_range_endpoint(expr, &mut ascriptions, &mut expanded_consts);
let mut lower_endpoint = |expr| self.lower_pattern_range_endpoint(expr, &mut ascriptions);
let lo = lower_endpoint(lo_expr)?.unwrap_or(PatRangeBoundary::NegInfinity);
let hi = lower_endpoint(hi_expr)?.unwrap_or(PatRangeBoundary::PosInfinity);
@ -282,10 +279,11 @@ impl<'tcx> PatCtxt<'tcx> {
let subpattern = Box::new(Pat { span, ty, kind });
kind = PatKind::AscribeUserType { ascription, subpattern };
}
for def_id in expanded_consts {
let subpattern = Box::new(Pat { span, ty, kind });
kind = PatKind::ExpandedConstant { def_id, subpattern };
}
// `PatKind::ExpandedConstant` wrappers from range endpoints used to
// also be preserved here, but that was only needed for unsafeck of
// inline `const { .. }` patterns, which were removed by
// <https://github.com/rust-lang/rust/pull/138492>.
Ok(kind)
}

View file

@ -45,6 +45,7 @@ impl const From<char> for u32 {
/// ```
/// let c = 'c';
/// let u = u32::from(c);
///
/// assert!(4 == size_of_val(&u))
/// ```
#[inline]
@ -63,6 +64,7 @@ impl const From<char> for u64 {
/// ```
/// let c = '👤';
/// let u = u64::from(c);
///
/// assert!(8 == size_of_val(&u))
/// ```
#[inline]
@ -83,6 +85,7 @@ impl const From<char> for u128 {
/// ```
/// let c = '⚙';
/// let u = u128::from(c);
///
/// assert!(16 == size_of_val(&u))
/// ```
#[inline]
@ -93,8 +96,8 @@ impl const From<char> for u128 {
}
}
/// Maps a `char` with code point in U+0000..=U+00FF to a byte in 0x00..=0xFF with same value,
/// failing if the code point is greater than U+00FF.
/// Maps a `char` with a code point from U+0000 to U+00FF (inclusive) to a byte in `0x00..=0xFF` with
/// the same value, failing if the code point is greater than U+00FF.
///
/// See [`impl From<u8> for char`](char#impl-From<u8>-for-char) for details on the encoding.
#[stable(feature = "u8_from_char", since = "1.59.0")]
@ -109,6 +112,7 @@ impl const TryFrom<char> for u8 {
/// ```
/// let a = 'ÿ'; // U+00FF
/// let b = 'Ā'; // U+0100
///
/// assert_eq!(u8::try_from(a), Ok(0xFF_u8));
/// assert!(u8::try_from(b).is_err());
/// ```
@ -122,8 +126,8 @@ impl const TryFrom<char> for u8 {
}
}
/// Maps a `char` with code point in U+0000..=U+FFFF to a `u16` in 0x0000..=0xFFFF with same value,
/// failing if the code point is greater than U+FFFF.
/// Maps a `char` with a code point from U+0000 to U+FFFF (inclusive) to a `u16` in `0x0000..=0xFFFF`
/// with the same value, failing if the code point is greater than U+FFFF.
///
/// This corresponds to the UCS-2 encoding, as specified in ISO/IEC 10646:2003.
#[stable(feature = "u16_from_char", since = "1.74.0")]
@ -138,6 +142,7 @@ impl const TryFrom<char> for u16 {
/// ```
/// let trans_rights = '⚧'; // U+26A7
/// let ninjas = '🥷'; // U+1F977
///
/// assert_eq!(u16::try_from(trans_rights), Ok(0x26A7_u16));
/// assert!(u16::try_from(ninjas).is_err());
/// ```
@ -151,7 +156,45 @@ impl const TryFrom<char> for u16 {
}
}
/// Maps a byte in 0x00..=0xFF to a `char` whose code point has the same value, in U+0000..=U+00FF.
/// Maps a `char` with a code point from U+0000 to U+10FFFF (inclusive) to a `usize` in
/// `0x0000..=0x10FFFF` with the same value, failing if the final value is unrepresentable by
/// `usize`.
///
/// Generally speaking, this conversion can be seen as obtaining the character's corresponding
/// UTF-32 code point to the extent representable by pointer addresses.
#[stable(feature = "usize_try_from_char", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
impl const TryFrom<char> for usize {
type Error = TryFromCharError;
/// Tries to convert a [`char`] into a [`usize`].
///
/// # Examples
///
/// ```
/// let a = '\u{FFFF}'; // Always succeeds.
/// let b = '\u{10FFFF}'; // Conditionally succeeds.
///
/// assert_eq!(usize::try_from(a), Ok(0xFFFF));
///
/// if size_of::<usize>() >= size_of::<u32>() {
/// assert_eq!(usize::try_from(b), Ok(0x10FFFF));
/// } else {
/// assert!(matches!(usize::try_from(b), Err(_)));
/// }
/// ```
#[inline]
fn try_from(c: char) -> Result<usize, Self::Error> {
// FIXME(const-hack): this should use map_err instead
match usize::try_from(u32::from(c)) {
Ok(x) => Ok(x),
Err(_) => Err(TryFromCharError(())),
}
}
}
/// Maps a byte in `0x00..=0xFF` to a `char` whose code point has the same value from U+0000 to U+00FF
/// (inclusive).
///
/// Unicode is designed such that this effectively decodes bytes
/// with the character encoding that IANA calls ISO-8859-1.
@ -179,6 +222,7 @@ impl const From<u8> for char {
/// ```
/// let u = 32 as u8;
/// let c = char::from(u);
///
/// assert!(4 == size_of_val(&c))
/// ```
#[inline]
@ -246,7 +290,6 @@ const fn char_try_from_u32(i: u32) -> Result<char, CharTryFromError> {
// Subtracting 0x800 causes 0x0000..0x0800 to wrap, meaning that a single
// unsigned comparison against 0x110000 - 0x800 will detect both the wrapped
// surrogate range as well as the numbers originally larger than 0x110000.
//
if (i ^ 0xD800).wrapping_sub(0x800) >= 0x110000 - 0x800 {
Err(CharTryFromError(()))
} else {

View file

@ -2166,7 +2166,7 @@ fn open_from(from: &Path) -> io::Result<(crate::fs::File, crate::fs::Metadata)>
fn set_times_impl(p: &CStr, times: FileTimes, follow_symlinks: bool) -> io::Result<()> {
cfg_select! {
any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "nuttx", target_os = "vita") => {
any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "nuttx", target_os = "vita", target_os = "rtems") => {
let _ = (p, times, follow_symlinks);
Err(io::const_error!(
io::ErrorKind::Unsupported,