Skip to content

Rollup of 8 pull requests #143459

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Jul 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/dependencies.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ env:
PR_TITLE: Weekly `cargo update`
PR_MESSAGE: |
Automation to keep dependencies in `Cargo.lock` current.
r? dep-bumps
The following is the output from `cargo update`:
COMMIT_MESSAGE: "cargo update \n\n"
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_attr_data_structures/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,9 @@ pub enum AttributeKind {
/// Represents `#[no_mangle]`
NoMangle(Span),

/// Represents `#[non_exhaustive]`
NonExhaustive(Span),

/// Represents `#[optimize(size|speed)]`
Optimize(OptimizeAttr, Span),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ impl AttributeKind {
Naked(..) => No,
NoImplicitPrelude(..) => No,
NoMangle(..) => No,
NonExhaustive(..) => Yes,
Optimize(..) => No,
PassByValue(..) => Yes,
PubTransparent(..) => Yes,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/src/attributes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub(crate) mod lint_helpers;
pub(crate) mod loop_match;
pub(crate) mod must_use;
pub(crate) mod no_implicit_prelude;
pub(crate) mod non_exhaustive;
pub(crate) mod repr;
pub(crate) mod rustc_internal;
pub(crate) mod semantics;
Expand Down
13 changes: 13 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use rustc_attr_data_structures::AttributeKind;
use rustc_span::{Span, Symbol, sym};

use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
use crate::context::Stage;

pub(crate) struct NonExhaustiveParser;

impl<S: Stage> NoArgsAttributeParser<S> for NonExhaustiveParser {
const PATH: &[Symbol] = &[sym::non_exhaustive];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NonExhaustive;
}
2 changes: 2 additions & 0 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use crate::attributes::lint_helpers::{AsPtrParser, PassByValueParser, PubTranspa
use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
use crate::attributes::must_use::MustUseParser;
use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
use crate::attributes::non_exhaustive::NonExhaustiveParser;
use crate::attributes::repr::{AlignParser, ReprParser};
use crate::attributes::rustc_internal::{
RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
Expand Down Expand Up @@ -144,6 +145,7 @@ attribute_parsers!(
Single<WithoutArgs<MayDangleParser>>,
Single<WithoutArgs<NoImplicitPreludeParser>>,
Single<WithoutArgs<NoMangleParser>>,
Single<WithoutArgs<NonExhaustiveParser>>,
Single<WithoutArgs<PassByValueParser>>,
Single<WithoutArgs<PubTransparentParser>>,
Single<WithoutArgs<TrackCallerParser>>,
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_data_structures/src/vec_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ impl SlotIndex {
index_in_bucket: idx as usize,
};
}
// SAFETY: We already ruled out idx 0, so `checked_ilog2` can't return `None`.
let bucket = unsafe { idx.checked_ilog2().unwrap_unchecked() as usize };
// We already ruled out idx 0, so this `ilog2` never panics (and the check optimizes away)
let bucket = idx.ilog2() as usize;
let entries = 1 << bucket;
SlotIndex {
bucket_idx: bucket - FIRST_BUCKET_SHIFT + 1,
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_expand/src/mbe/macro_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,15 @@ pub fn compile_declarative_macro(
if let Err(e) = p.expect(exp!(FatArrow)) {
return dummy_syn_ext(e.emit());
}
if p.token == token::Eof {
let err_sp = p.token.span.shrink_to_hi();
let guar = sess
.dcx()
.struct_span_err(err_sp, "macro definition ended unexpectedly")
.with_span_label(err_sp, "expected right-hand side of macro rule")
.emit();
return dummy_syn_ext(guar);
}
let rhs_tt = p.parse_token_tree();
let rhs_tt = mbe::quoted::parse(
&TokenStream::new(vec![rhs_tt]),
Expand Down
8 changes: 5 additions & 3 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -779,9 +779,11 @@ fn lower_variant<'tcx>(
fields,
parent_did.to_def_id(),
recovered,
adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, sym::non_exhaustive)
|| variant_did
.is_some_and(|variant_did| tcx.has_attr(variant_did, sym::non_exhaustive)),
adt_kind == AdtKind::Struct
&& find_attr!(tcx.get_all_attrs(parent_did), AttributeKind::NonExhaustive(..))
|| variant_did.is_some_and(|variant_did| {
find_attr!(tcx.get_all_attrs(variant_did), AttributeKind::NonExhaustive(..))
}),
)
}

Expand Down
3 changes: 0 additions & 3 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2264,9 +2264,6 @@ rustc_queries! {
query maybe_unused_trait_imports(_: ()) -> &'tcx FxIndexSet<LocalDefId> {
desc { "fetching potentially unused trait imports" }
}
query names_imported_by_glob_use(def_id: LocalDefId) -> &'tcx FxIndexSet<Symbol> {
desc { |tcx| "finding names imported by glob use for `{}`", tcx.def_path_str(def_id) }
}

query stability_index(_: ()) -> &'tcx stability::Index {
arena_cache
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_middle/src/ty/adt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::ops::Range;
use std::str;

use rustc_abi::{FIRST_VARIANT, ReprOptions, VariantIdx};
use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::intern::Interned;
Expand Down Expand Up @@ -278,7 +279,9 @@ impl AdtDefData {
debug!("AdtDef::new({:?}, {:?}, {:?}, {:?})", did, kind, variants, repr);
let mut flags = AdtFlags::NO_ADT_FLAGS;

if kind == AdtKind::Enum && tcx.has_attr(did, sym::non_exhaustive) {
if kind == AdtKind::Enum
&& find_attr!(tcx.get_all_attrs(did), AttributeKind::NonExhaustive(..))
{
debug!("found non-exhaustive variant list for {:?}", did);
flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE;
}
Expand Down
4 changes: 0 additions & 4 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3417,10 +3417,6 @@ pub struct DeducedParamAttrs {
pub fn provide(providers: &mut Providers) {
providers.maybe_unused_trait_imports =
|tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports;
providers.names_imported_by_glob_use = |tcx, id| {
tcx.arena.alloc(tcx.resolutions(()).glob_map.get(&id).cloned().unwrap_or_default())
};

providers.extern_mod_stmt_cnum =
|tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned();
providers.is_panic_runtime =
Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_mir_build/src/thir/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,9 +319,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
}
PatKind::Deref { subpattern }
}
hir::PatKind::Box(subpattern) => {
PatKind::Deref { subpattern: self.lower_pattern(subpattern) }
}
hir::PatKind::Box(subpattern) => PatKind::DerefPattern {
subpattern: self.lower_pattern(subpattern),
borrow: hir::ByRef::No,
},

hir::PatKind::Slice(prefix, slice, suffix) => {
self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_parse/src/validate_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ fn emit_malformed_attribute(
| sym::rustc_allow_const_fn_unstable
| sym::naked
| sym::no_mangle
| sym::non_exhaustive
| sym::must_use
| sym::track_caller
| sym::link_name
Expand Down
16 changes: 8 additions & 8 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
Attribute::Parsed(AttributeKind::TrackCaller(attr_span)) => {
self.check_track_caller(hir_id, *attr_span, attrs, span, target)
}
Attribute::Parsed(AttributeKind::NonExhaustive(attr_span)) => {
self.check_non_exhaustive(hir_id, *attr_span, span, target, item)
}
Attribute::Parsed(
AttributeKind::RustcLayoutScalarValidRangeStart(_num, attr_span)
| AttributeKind::RustcLayoutScalarValidRangeEnd(_num, attr_span),
Expand Down Expand Up @@ -237,7 +240,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
[sym::no_sanitize, ..] => {
self.check_no_sanitize(attr, span, target)
}
[sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target, item),
[sym::marker, ..] => self.check_marker(hir_id, attr, span, target),
[sym::thread_local, ..] => self.check_thread_local(attr, span, target),
[sym::doc, ..] => self.check_doc_attrs(
Expand Down Expand Up @@ -779,7 +781,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
fn check_non_exhaustive(
&self,
hir_id: HirId,
attr: &Attribute,
attr_span: Span,
span: Span,
target: Target,
item: Option<ItemLike<'_>>,
Expand All @@ -794,7 +796,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
&& fields.iter().any(|f| f.default.is_some())
{
self.dcx().emit_err(errors::NonExhaustiveWithDefaultFieldValues {
attr_span: attr.span(),
attr_span,
defn_span: span,
});
}
Expand All @@ -805,13 +807,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
// erroneously allowed it and some crates used it accidentally, to be compatible
// with crates depending on them, we can't throw an error here.
Target::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "non_exhaustive");
self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "non_exhaustive");
}
_ => {
self.dcx().emit_err(errors::NonExhaustiveWrongLocation {
attr_span: attr.span(),
defn_span: span,
});
self.dcx()
.emit_err(errors::NonExhaustiveWrongLocation { attr_span, defn_span: span });
}
}
}
Expand Down
87 changes: 24 additions & 63 deletions compiler/rustc_pattern_analysis/src/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,27 +221,19 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
let slice = match ctor {
Struct | Variant(_) | UnionField => match ty.kind() {
ty::Tuple(fs) => reveal_and_alloc(cx, fs.iter()),
ty::Adt(adt, args) => {
if adt.is_box() {
// The only legal patterns of type `Box` (outside `std`) are `_` and box
// patterns. If we're here we can assume this is a box pattern.
reveal_and_alloc(cx, once(args.type_at(0)))
} else {
let variant =
&adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt));
let tys = cx.variant_sub_tys(ty, variant).map(|(field, ty)| {
let is_visible =
adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
let is_uninhabited = cx.is_uninhabited(*ty);
let is_unstable =
cx.tcx.lookup_stability(field.did).is_some_and(|stab| {
stab.is_unstable() && stab.feature != sym::rustc_private
});
let skip = is_uninhabited && (!is_visible || is_unstable);
(ty, PrivateUninhabitedField(skip))
ty::Adt(adt, _) => {
let variant = &adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt));
let tys = cx.variant_sub_tys(ty, variant).map(|(field, ty)| {
let is_visible =
adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
let is_uninhabited = cx.is_uninhabited(*ty);
let is_unstable = cx.tcx.lookup_stability(field.did).is_some_and(|stab| {
stab.is_unstable() && stab.feature != sym::rustc_private
});
cx.dropless_arena.alloc_from_iter(tys)
}
let skip = is_uninhabited && (!is_visible || is_unstable);
(ty, PrivateUninhabitedField(skip))
});
cx.dropless_arena.alloc_from_iter(tys)
}
_ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"),
},
Expand Down Expand Up @@ -273,14 +265,8 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
Struct | Variant(_) | UnionField => match ty.kind() {
ty::Tuple(fs) => fs.len(),
ty::Adt(adt, ..) => {
if adt.is_box() {
// The only legal patterns of type `Box` (outside `std`) are `_` and box
// patterns. If we're here we can assume this is a box pattern.
1
} else {
let variant_idx = RustcPatCtxt::variant_index_for_adt(&ctor, *adt);
adt.variant(variant_idx).fields.len()
}
let variant_idx = RustcPatCtxt::variant_index_for_adt(&ctor, *adt);
adt.variant(variant_idx).fields.len()
}
_ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"),
},
Expand Down Expand Up @@ -470,8 +456,6 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
fields = vec![self.lower_pat(subpattern).at_index(0)];
arity = 1;
ctor = match ty.kind() {
// This is a box pattern.
ty::Adt(adt, ..) if adt.is_box() => Struct,
ty::Ref(..) => Ref,
_ => span_bug!(
pat.span,
Expand Down Expand Up @@ -501,28 +485,6 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
.map(|ipat| self.lower_pat(&ipat.pattern).at_index(ipat.field.index()))
.collect();
}
ty::Adt(adt, _) if adt.is_box() => {
// The only legal patterns of type `Box` (outside `std`) are `_` and box
// patterns. If we're here we can assume this is a box pattern.
// FIXME(Nadrieril): A `Box` can in theory be matched either with `Box(_,
// _)` or a box pattern. As a hack to avoid an ICE with the former, we
// ignore other fields than the first one. This will trigger an error later
// anyway.
// See https://github.com/rust-lang/rust/issues/82772,
// explanation: https://github.com/rust-lang/rust/pull/82789#issuecomment-796921977
// The problem is that we can't know from the type whether we'll match
// normally or through box-patterns. We'll have to figure out a proper
// solution when we introduce generalized deref patterns. Also need to
// prevent mixing of those two options.
let pattern = subpatterns.into_iter().find(|pat| pat.field.index() == 0);
if let Some(pat) = pattern {
fields = vec![self.lower_pat(&pat.pattern).at_index(0)];
} else {
fields = vec![];
}
ctor = Struct;
arity = 1;
}
ty::Adt(adt, _) => {
ctor = match pat.kind {
PatKind::Leaf { .. } if adt.is_union() => UnionField,
Expand Down Expand Up @@ -825,11 +787,6 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
Bool(b) => b.to_string(),
Str(s) => s.to_string(),
IntRange(range) => return self.print_pat_range(range, *pat.ty()),
Struct if pat.ty().is_box() => {
// Outside of the `alloc` crate, the only way to create a struct pattern
// of type `Box` is to use a `box` pattern via #[feature(box_patterns)].
format!("box {}", print(&pat.fields[0]))
}
Struct | Variant(_) | UnionField => {
let enum_info = match *pat.ty().kind() {
ty::Adt(adt_def, _) if adt_def.is_enum() => EnumInfo::Enum {
Expand Down Expand Up @@ -866,6 +823,14 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
print::write_ref_like(&mut s, pat.ty().inner(), &print(&pat.fields[0])).unwrap();
s
}
DerefPattern(_) if pat.ty().is_box() && !self.tcx.features().deref_patterns() => {
// FIXME(deref_patterns): Remove this special handling once `box_patterns` is gone.
// HACK(@dianne): `box _` syntax is exposed on stable in diagnostics, e.g. to
// witness non-exhaustiveness of `match Box::new(0) { Box { .. } if false => {} }`.
// To avoid changing diagnostics before deref pattern syntax is finalized, let's use
// `box _` syntax unless `deref_patterns` is enabled.
format!("box {}", print(&pat.fields[0]))
}
DerefPattern(_) => format!("deref!({})", print(&pat.fields[0])),
Slice(slice) => {
let (prefix_len, has_dot_dot) = match slice.kind {
Expand Down Expand Up @@ -964,12 +929,8 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
ty: &Self::Ty,
) -> fmt::Result {
if let ty::Adt(adt, _) = ty.kind() {
if adt.is_box() {
write!(f, "Box")?
} else {
let variant = adt.variant(Self::variant_index_for_adt(ctor, *adt));
write!(f, "{}", variant.name)?;
}
let variant = adt.variant(Self::variant_index_for_adt(ctor, *adt));
write!(f, "{}", variant.name)?;
}
Ok(())
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_resolve/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use rustc_ast::{
self as ast, CRATE_NODE_ID, Crate, ItemKind, MetaItemInner, MetaItemKind, ModKind, NodeId, Path,
};
use rustc_ast_pretty::pprust;
use rustc_attr_data_structures::{self as attr, Stability};
use rustc_attr_data_structures::{self as attr, AttributeKind, Stability, find_attr};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_errors::codes::*;
Expand Down Expand Up @@ -1998,9 +1998,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// Otherwise, point out if the struct has any private fields.
if let Some(def_id) = res.opt_def_id()
&& !def_id.is_local()
&& let Some(attr) = self.tcx.get_attr(def_id, sym::non_exhaustive)
&& let Some(attr_span) = find_attr!(self.tcx.get_all_attrs(def_id), AttributeKind::NonExhaustive(span) => *span)
{
non_exhaustive = Some(attr.span());
non_exhaustive = Some(attr_span);
} else if let Some(span) = ctor_fields_span {
let label = errors::ConstructorPrivateIfAnyFieldPrivate { span };
err.subdiagnostic(label);
Expand Down
Loading
Loading