From 9a7db566d7b7bb534c5dc3bcfbd2ddd51d99a8d5 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Tue, 1 Jul 2025 02:45:14 +0500 Subject: [PATCH 01/10] moved tests --- .../output-slot-init-vs-noninit.rs} | 0 .../remark-flag-functionality.rs} | 0 .../shift-right-operand-mutation.rs} | 0 .../{out-pointer-aliasing.rs => codegen/sret-aliasing-rules.rs} | 0 tests/ui/{paren-span.rs => macros/macro-paren-span-diagnostic.rs} | 0 .../macro-paren-span-diagnostic.stderr} | 0 .../panic-during-display-formatting.rs} | 0 .../panic-handler-closures.rs} | 0 .../ufcs-return-unused-parens.fixed} | 0 .../ui/{path-lookahead.rs => parser/ufcs-return-unused-parens.rs} | 0 .../ufcs-return-unused-parens.stderr} | 0 .../partialeq-ref-mismatch-diagnostic.rs} | 0 .../partialeq-ref-mismatch-diagnostic.stderr} | 0 13 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{output-slot-variants.rs => codegen/output-slot-init-vs-noninit.rs} (100%) rename tests/ui/{optimization-remark.rs => codegen/remark-flag-functionality.rs} (100%) rename tests/ui/{over-constrained-vregs.rs => codegen/shift-right-operand-mutation.rs} (100%) rename tests/ui/{out-pointer-aliasing.rs => codegen/sret-aliasing-rules.rs} (100%) rename tests/ui/{paren-span.rs => macros/macro-paren-span-diagnostic.rs} (100%) rename tests/ui/{paren-span.stderr => macros/macro-paren-span-diagnostic.stderr} (100%) rename tests/ui/{panic-while-printing.rs => panics/panic-during-display-formatting.rs} (100%) rename tests/ui/{panic_implementation-closures.rs => panics/panic-handler-closures.rs} (100%) rename tests/ui/{path-lookahead.fixed => parser/ufcs-return-unused-parens.fixed} (100%) rename tests/ui/{path-lookahead.rs => parser/ufcs-return-unused-parens.rs} (100%) rename tests/ui/{path-lookahead.stderr => parser/ufcs-return-unused-parens.stderr} (100%) rename tests/ui/{partialeq_help.rs => traits/partialeq-ref-mismatch-diagnostic.rs} (100%) rename tests/ui/{partialeq_help.stderr => traits/partialeq-ref-mismatch-diagnostic.stderr} (100%) diff --git a/tests/ui/output-slot-variants.rs b/tests/ui/codegen/output-slot-init-vs-noninit.rs similarity index 100% rename from tests/ui/output-slot-variants.rs rename to tests/ui/codegen/output-slot-init-vs-noninit.rs diff --git a/tests/ui/optimization-remark.rs b/tests/ui/codegen/remark-flag-functionality.rs similarity index 100% rename from tests/ui/optimization-remark.rs rename to tests/ui/codegen/remark-flag-functionality.rs diff --git a/tests/ui/over-constrained-vregs.rs b/tests/ui/codegen/shift-right-operand-mutation.rs similarity index 100% rename from tests/ui/over-constrained-vregs.rs rename to tests/ui/codegen/shift-right-operand-mutation.rs diff --git a/tests/ui/out-pointer-aliasing.rs b/tests/ui/codegen/sret-aliasing-rules.rs similarity index 100% rename from tests/ui/out-pointer-aliasing.rs rename to tests/ui/codegen/sret-aliasing-rules.rs diff --git a/tests/ui/paren-span.rs b/tests/ui/macros/macro-paren-span-diagnostic.rs similarity index 100% rename from tests/ui/paren-span.rs rename to tests/ui/macros/macro-paren-span-diagnostic.rs diff --git a/tests/ui/paren-span.stderr b/tests/ui/macros/macro-paren-span-diagnostic.stderr similarity index 100% rename from tests/ui/paren-span.stderr rename to tests/ui/macros/macro-paren-span-diagnostic.stderr diff --git a/tests/ui/panic-while-printing.rs b/tests/ui/panics/panic-during-display-formatting.rs similarity index 100% rename from tests/ui/panic-while-printing.rs rename to tests/ui/panics/panic-during-display-formatting.rs diff --git a/tests/ui/panic_implementation-closures.rs b/tests/ui/panics/panic-handler-closures.rs similarity index 100% rename from tests/ui/panic_implementation-closures.rs rename to tests/ui/panics/panic-handler-closures.rs diff --git a/tests/ui/path-lookahead.fixed b/tests/ui/parser/ufcs-return-unused-parens.fixed similarity index 100% rename from tests/ui/path-lookahead.fixed rename to tests/ui/parser/ufcs-return-unused-parens.fixed diff --git a/tests/ui/path-lookahead.rs b/tests/ui/parser/ufcs-return-unused-parens.rs similarity index 100% rename from tests/ui/path-lookahead.rs rename to tests/ui/parser/ufcs-return-unused-parens.rs diff --git a/tests/ui/path-lookahead.stderr b/tests/ui/parser/ufcs-return-unused-parens.stderr similarity index 100% rename from tests/ui/path-lookahead.stderr rename to tests/ui/parser/ufcs-return-unused-parens.stderr diff --git a/tests/ui/partialeq_help.rs b/tests/ui/traits/partialeq-ref-mismatch-diagnostic.rs similarity index 100% rename from tests/ui/partialeq_help.rs rename to tests/ui/traits/partialeq-ref-mismatch-diagnostic.rs diff --git a/tests/ui/partialeq_help.stderr b/tests/ui/traits/partialeq-ref-mismatch-diagnostic.stderr similarity index 100% rename from tests/ui/partialeq_help.stderr rename to tests/ui/traits/partialeq-ref-mismatch-diagnostic.stderr From 15286f220e54e39dc533e43a492679e957bf332b Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 3 Jul 2025 17:42:43 -0700 Subject: [PATCH 02/10] Remove some unnecessary `unsafe` in VecCache --- compiler/rustc_data_structures/src/vec_cache.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_data_structures/src/vec_cache.rs b/compiler/rustc_data_structures/src/vec_cache.rs index 3b448c056b748..df83d15b5f943 100644 --- a/compiler/rustc_data_structures/src/vec_cache.rs +++ b/compiler/rustc_data_structures/src/vec_cache.rs @@ -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, From 0403990000438742065e54c4cae9bb1afb0e6038 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 3 Jul 2025 20:53:10 -0700 Subject: [PATCH 03/10] mbe: Gracefully handle macro rules that end after `=>` Add a test for various cases of invalid macro definitions. Closes: https://github.com/rust-lang/rust/issues/143351 --- compiler/rustc_expand/src/mbe/macro_rules.rs | 9 +++ tests/ui/parser/macro/bad-macro-definition.rs | 22 ++++++++ .../parser/macro/bad-macro-definition.stderr | 56 +++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 tests/ui/parser/macro/bad-macro-definition.rs create mode 100644 tests/ui/parser/macro/bad-macro-definition.stderr diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index dad2fd99ef205..2ffd4e3cf285e 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -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]), diff --git a/tests/ui/parser/macro/bad-macro-definition.rs b/tests/ui/parser/macro/bad-macro-definition.rs new file mode 100644 index 0000000000000..3c5c93ea3b3e4 --- /dev/null +++ b/tests/ui/parser/macro/bad-macro-definition.rs @@ -0,0 +1,22 @@ +#![crate_type = "lib"] + +macro_rules! a { {} => } +//~^ ERROR: macro definition ended unexpectedly + +macro_rules! b { 0 => } +//~^ ERROR: macro definition ended unexpectedly +//~| ERROR: invalid macro matcher + +macro_rules! c { x => } +//~^ ERROR: macro definition ended unexpectedly +//~| ERROR: invalid macro matcher + +macro_rules! d { _ => } +//~^ ERROR: macro definition ended unexpectedly +//~| ERROR: invalid macro matcher + +macro_rules! e { {} } +//~^ ERROR: expected `=>`, found end of macro arguments + +macro_rules! f {} +//~^ ERROR: macros must contain at least one rule diff --git a/tests/ui/parser/macro/bad-macro-definition.stderr b/tests/ui/parser/macro/bad-macro-definition.stderr new file mode 100644 index 0000000000000..de6d9d6a38b15 --- /dev/null +++ b/tests/ui/parser/macro/bad-macro-definition.stderr @@ -0,0 +1,56 @@ +error: macro definition ended unexpectedly + --> $DIR/bad-macro-definition.rs:3:23 + | +LL | macro_rules! a { {} => } + | ^ expected right-hand side of macro rule + +error: invalid macro matcher; matchers must be contained in balanced delimiters + --> $DIR/bad-macro-definition.rs:6:18 + | +LL | macro_rules! b { 0 => } + | ^ + +error: macro definition ended unexpectedly + --> $DIR/bad-macro-definition.rs:6:22 + | +LL | macro_rules! b { 0 => } + | ^ expected right-hand side of macro rule + +error: invalid macro matcher; matchers must be contained in balanced delimiters + --> $DIR/bad-macro-definition.rs:10:18 + | +LL | macro_rules! c { x => } + | ^ + +error: macro definition ended unexpectedly + --> $DIR/bad-macro-definition.rs:10:22 + | +LL | macro_rules! c { x => } + | ^ expected right-hand side of macro rule + +error: invalid macro matcher; matchers must be contained in balanced delimiters + --> $DIR/bad-macro-definition.rs:14:18 + | +LL | macro_rules! d { _ => } + | ^ + +error: macro definition ended unexpectedly + --> $DIR/bad-macro-definition.rs:14:22 + | +LL | macro_rules! d { _ => } + | ^ expected right-hand side of macro rule + +error: expected `=>`, found end of macro arguments + --> $DIR/bad-macro-definition.rs:18:20 + | +LL | macro_rules! e { {} } + | ^ expected `=>` + +error: macros must contain at least one rule + --> $DIR/bad-macro-definition.rs:21:1 + | +LL | macro_rules! f {} + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 9 previous errors + From b33dc21d78821ac0fc33241d96badb64a001e0fd Mon Sep 17 00:00:00 2001 From: clubby789 Date: Thu, 3 Jul 2025 17:22:31 +0100 Subject: [PATCH 04/10] Assign dependency bump PRs to me --- .github/workflows/dependencies.yml | 1 + triagebot.toml | 3 +++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml index 98d8c14f7d185..9d4b6192d6eae 100644 --- a/.github/workflows/dependencies.yml +++ b/.github/workflows/dependencies.yml @@ -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" diff --git a/triagebot.toml b/triagebot.toml index 6385528e7b6ed..23defca5c5002 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1350,6 +1350,9 @@ project-exploit-mitigations = [ compiletest = [ "@jieyouxu", ] +dep-bumps = [ + "@clubby789", +] [assign.owners] "/.github/workflows" = ["infra-ci"] From 98659a339dd7203e0f23871b327b9305940e0d61 Mon Sep 17 00:00:00 2001 From: dianne Date: Fri, 4 Jul 2025 01:23:36 -0700 Subject: [PATCH 05/10] treat box patterns as deref patterns in THIR and usefulness analysis This removes special-casing of boxes from `rustc_pattern_analysis`, as a first step in replacing `box_patterns` with `deref_patterns`. Incidentally, it fixes a bug caused by box patterns being represented as structs rather than pointers, where `exhaustive_patterns` could generate spurious `unreachable_patterns` lints on arms required for exhaustiveness; following the lint's advice would result in an error. --- .../rustc_mir_build/src/thir/pattern/mod.rs | 7 +- compiler/rustc_pattern_analysis/src/rustc.rs | 87 +++++-------------- tests/ui/uninhabited/uninhabited-patterns.rs | 6 +- .../uninhabited/uninhabited-patterns.stderr | 36 +++++--- 4 files changed, 55 insertions(+), 81 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index e44a440b5c13c..a44afed5492d3 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -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) diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 46ced7500ea20..e53cebc59baf3 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -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:?}"), }, @@ -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:?}"), }, @@ -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, @@ -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, @@ -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 { @@ -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 { @@ -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(()) } diff --git a/tests/ui/uninhabited/uninhabited-patterns.rs b/tests/ui/uninhabited/uninhabited-patterns.rs index b7429464fa5a0..1f30af2acc697 100644 --- a/tests/ui/uninhabited/uninhabited-patterns.rs +++ b/tests/ui/uninhabited/uninhabited-patterns.rs @@ -27,7 +27,11 @@ fn main() { let x: Result, &[Result]> = Err(&[]); match x { - Ok(box _) => (), //~ ERROR unreachable pattern + Ok(box _) => (), // We'd get a non-exhaustiveness error if this arm was removed; don't lint. + Err(&[]) => (), + Err(&[..]) => (), + } + match x { //~ ERROR non-exhaustive patterns Err(&[]) => (), Err(&[..]) => (), } diff --git a/tests/ui/uninhabited/uninhabited-patterns.stderr b/tests/ui/uninhabited/uninhabited-patterns.stderr index 7a872767d959a..62113c82a3648 100644 --- a/tests/ui/uninhabited/uninhabited-patterns.stderr +++ b/tests/ui/uninhabited/uninhabited-patterns.stderr @@ -1,21 +1,23 @@ -error: unreachable pattern - --> $DIR/uninhabited-patterns.rs:30:9 +error[E0004]: non-exhaustive patterns: `Ok(_)` not covered + --> $DIR/uninhabited-patterns.rs:34:11 | -LL | Ok(box _) => (), - | ^^^^^^^^^------- - | | - | matches no values because `NotSoSecretlyEmpty` is uninhabited - | help: remove the match arm +LL | match x { + | ^ pattern `Ok(_)` not covered | - = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types -note: the lint level is defined here - --> $DIR/uninhabited-patterns.rs:4:9 +note: `Result, &[Result]>` defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + ::: $SRC_DIR/core/src/result.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Result, &[Result]>` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ Err(&[..]) => (), +LL ~ Ok(_) => todo!(), | -LL | #![deny(unreachable_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/uninhabited-patterns.rs:39:9 + --> $DIR/uninhabited-patterns.rs:43:9 | LL | Err(Ok(_y)) => (), | ^^^^^^^^^^^------- @@ -24,9 +26,14 @@ LL | Err(Ok(_y)) => (), | help: remove the match arm | = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types +note: the lint level is defined here + --> $DIR/uninhabited-patterns.rs:4:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/uninhabited-patterns.rs:42:15 + --> $DIR/uninhabited-patterns.rs:46:15 | LL | while let Some(_y) = foo() { | ^^^^^^^^ matches no values because `NotSoSecretlyEmpty` is uninhabited @@ -35,3 +42,4 @@ LL | while let Some(_y) = foo() { error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0004`. From 2d3ff91add77a2ae5959f5134e12f5c0eec59ce5 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 3 Jul 2025 13:42:36 +0000 Subject: [PATCH 06/10] Remove names_imported_by_glob_use query. --- compiler/rustc_middle/src/query/mod.rs | 3 --- compiler/rustc_middle/src/ty/context.rs | 4 ---- src/tools/clippy/clippy_lints/src/wildcard_imports.rs | 2 +- 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index aefae3a3b1466..17a29c9ae4b21 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2264,9 +2264,6 @@ rustc_queries! { query maybe_unused_trait_imports(_: ()) -> &'tcx FxIndexSet { desc { "fetching potentially unused trait imports" } } - query names_imported_by_glob_use(def_id: LocalDefId) -> &'tcx FxIndexSet { - desc { |tcx| "finding names imported by glob use for `{}`", tcx.def_path_str(def_id) } - } query stability_index(_: ()) -> &'tcx stability::Index { arena_cache diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 8aa50d14faa61..9518757c5ae12 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -3413,10 +3413,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 = diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs index d9dda6eadb2a5..22fd15d153abc 100644 --- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs +++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs @@ -130,7 +130,7 @@ impl LateLintPass<'_> for WildcardImports { } if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind && (self.warn_on_all || !self.check_exceptions(cx, item, use_path.segments)) - && let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id) + && let Some(used_imports) = cx.tcx.resolutions(()).glob_map.get(&item.owner_id.def_id) && !used_imports.is_empty() // Already handled by `unused_imports` && !used_imports.contains(&kw::Underscore) { From f4ef1a769a4bc67089b0c2c93c6ff891daed4385 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Sun, 25 May 2025 12:21:27 +0530 Subject: [PATCH 07/10] std: sys: net: uefi: tcp4: Implement write A blocking implementation of tcp4 write. Signed-off-by: Ayush Singh --- .../std/src/sys/net/connection/uefi/mod.rs | 11 ++--- .../std/src/sys/net/connection/uefi/tcp.rs | 8 +++- .../std/src/sys/net/connection/uefi/tcp4.rs | 40 +++++++++++++++++++ 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs index 46d67c8e51019..2d465bd0efaa3 100644 --- a/library/std/src/sys/net/connection/uefi/mod.rs +++ b/library/std/src/sys/net/connection/uefi/mod.rs @@ -7,7 +7,7 @@ use crate::time::Duration; mod tcp; pub(crate) mod tcp4; -pub struct TcpStream(#[expect(dead_code)] tcp::Tcp); +pub struct TcpStream(tcp::Tcp); impl TcpStream { pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result { @@ -54,12 +54,13 @@ impl TcpStream { false } - pub fn write(&self, _: &[u8]) -> io::Result { - unsupported() + pub fn write(&self, buf: &[u8]) -> io::Result { + self.0.write(buf) } - pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result { - unsupported() + pub fn write_vectored(&self, buf: &[IoSlice<'_>]) -> io::Result { + // FIXME: UEFI does support vectored write, so implement that. + crate::io::default_write_vectored(|b| self.write(b), buf) } pub fn is_write_vectored(&self) -> bool { diff --git a/library/std/src/sys/net/connection/uefi/tcp.rs b/library/std/src/sys/net/connection/uefi/tcp.rs index f87accdc41de8..9c3462e3468cd 100644 --- a/library/std/src/sys/net/connection/uefi/tcp.rs +++ b/library/std/src/sys/net/connection/uefi/tcp.rs @@ -3,7 +3,7 @@ use crate::io; use crate::net::SocketAddr; pub(crate) enum Tcp { - V4(#[expect(dead_code)] tcp4::Tcp4), + V4(tcp4::Tcp4), } impl Tcp { @@ -18,4 +18,10 @@ impl Tcp { SocketAddr::V6(_) => todo!(), } } + + pub(crate) fn write(&self, buf: &[u8]) -> io::Result { + match self { + Self::V4(client) => client.write(buf), + } + } } diff --git a/library/std/src/sys/net/connection/uefi/tcp4.rs b/library/std/src/sys/net/connection/uefi/tcp4.rs index f7ca373b52b5a..d0f0d27d975f3 100644 --- a/library/std/src/sys/net/connection/uefi/tcp4.rs +++ b/library/std/src/sys/net/connection/uefi/tcp4.rs @@ -88,6 +88,46 @@ impl Tcp4 { } } + pub(crate) fn write(&self, buf: &[u8]) -> io::Result { + let evt = unsafe { self.create_evt() }?; + let completion_token = + tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS }; + let data_len = u32::try_from(buf.len()).unwrap_or(u32::MAX); + + let fragment = tcp4::FragmentData { + fragment_length: data_len, + fragment_buffer: buf.as_ptr().cast::().cast_mut(), + }; + let mut tx_data = tcp4::TransmitData { + push: r_efi::efi::Boolean::FALSE, + urgent: r_efi::efi::Boolean::FALSE, + data_length: data_len, + fragment_count: 1, + fragment_table: [fragment], + }; + + let protocol = self.protocol.as_ptr(); + let mut token = tcp4::IoToken { + completion_token, + packet: tcp4::IoTokenPacket { + tx_data: (&raw mut tx_data).cast::>(), + }, + }; + + let r = unsafe { ((*protocol).transmit)(protocol, &mut token) }; + if r.is_error() { + return Err(io::Error::from_raw_os_error(r.as_usize())); + } + + self.wait_for_flag(); + + if completion_token.status.is_error() { + Err(io::Error::from_raw_os_error(completion_token.status.as_usize())) + } else { + Ok(data_len as usize) + } + } + unsafe fn create_evt(&self) -> io::Result { self.flag.store(false, Ordering::Relaxed); helpers::OwnedEvent::new( From 71176a28e698d04b23a3e20d8a8d93de4d467609 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Fri, 4 Jul 2025 19:14:26 +0200 Subject: [PATCH 08/10] clean up GVN TypeId test --- ...onst_eval_polymorphic.no_optimize.GVN.diff | 12 ++++ ...t_eval_polymorphic.optimize_false.GVN.diff | 13 +++++ ...st_eval_polymorphic.optimize_true.GVN.diff | 13 +++++ tests/mir-opt/gvn_const_eval_polymorphic.rs | 57 +++++++++++++++++++ ...type_id_polymorphic.cursed_is_i32.GVN.diff | 12 ---- tests/mir-opt/gvn_type_id_polymorphic.rs | 22 ------- 6 files changed, 95 insertions(+), 34 deletions(-) create mode 100644 tests/mir-opt/gvn_const_eval_polymorphic.no_optimize.GVN.diff create mode 100644 tests/mir-opt/gvn_const_eval_polymorphic.optimize_false.GVN.diff create mode 100644 tests/mir-opt/gvn_const_eval_polymorphic.optimize_true.GVN.diff create mode 100644 tests/mir-opt/gvn_const_eval_polymorphic.rs delete mode 100644 tests/mir-opt/gvn_type_id_polymorphic.cursed_is_i32.GVN.diff delete mode 100644 tests/mir-opt/gvn_type_id_polymorphic.rs diff --git a/tests/mir-opt/gvn_const_eval_polymorphic.no_optimize.GVN.diff b/tests/mir-opt/gvn_const_eval_polymorphic.no_optimize.GVN.diff new file mode 100644 index 0000000000000..a91561ba304b8 --- /dev/null +++ b/tests/mir-opt/gvn_const_eval_polymorphic.no_optimize.GVN.diff @@ -0,0 +1,12 @@ +- // MIR for `no_optimize` before GVN ++ // MIR for `no_optimize` after GVN + + fn no_optimize() -> bool { + let mut _0: bool; + + bb0: { + _0 = Eq(const no_optimize::::{constant#0}, const no_optimize::::{constant#1}); + return; + } + } + diff --git a/tests/mir-opt/gvn_const_eval_polymorphic.optimize_false.GVN.diff b/tests/mir-opt/gvn_const_eval_polymorphic.optimize_false.GVN.diff new file mode 100644 index 0000000000000..bdfa2987b23cd --- /dev/null +++ b/tests/mir-opt/gvn_const_eval_polymorphic.optimize_false.GVN.diff @@ -0,0 +1,13 @@ +- // MIR for `optimize_false` before GVN ++ // MIR for `optimize_false` after GVN + + fn optimize_false() -> bool { + let mut _0: bool; + + bb0: { +- _0 = Eq(const optimize_false::::{constant#0}, const optimize_false::::{constant#1}); ++ _0 = const false; + return; + } + } + diff --git a/tests/mir-opt/gvn_const_eval_polymorphic.optimize_true.GVN.diff b/tests/mir-opt/gvn_const_eval_polymorphic.optimize_true.GVN.diff new file mode 100644 index 0000000000000..dc337d43fb04d --- /dev/null +++ b/tests/mir-opt/gvn_const_eval_polymorphic.optimize_true.GVN.diff @@ -0,0 +1,13 @@ +- // MIR for `optimize_true` before GVN ++ // MIR for `optimize_true` after GVN + + fn optimize_true() -> bool { + let mut _0: bool; + + bb0: { +- _0 = Eq(const optimize_true::::{constant#0}, const optimize_true::::{constant#1}); ++ _0 = const true; + return; + } + } + diff --git a/tests/mir-opt/gvn_const_eval_polymorphic.rs b/tests/mir-opt/gvn_const_eval_polymorphic.rs new file mode 100644 index 0000000000000..7320ad947ff2e --- /dev/null +++ b/tests/mir-opt/gvn_const_eval_polymorphic.rs @@ -0,0 +1,57 @@ +//@ test-mir-pass: GVN +//@ compile-flags: --crate-type lib + +//! Regressions test for a mis-optimization where some functions +//! (`type_id` / `type_name` / `needs_drop`) could be evaluated in +//! a generic context, even though their value depends on some type +//! parameter `T`. +//! +//! In particular, `type_name_of_val(&generic::)` was incorrectly +//! evaluated to the string "crate_name::generic::", and +//! `no_optimize` was incorrectly optimized to `false`. + +#![feature(const_type_name)] + +fn generic() {} + +const fn type_name_contains_i32(_: &T) -> bool { + let pattern = b"i32"; + let name = std::any::type_name::().as_bytes(); + let mut i = 0; + 'outer: while i < name.len() - pattern.len() + 1 { + let mut j = 0; + while j < pattern.len() { + if name[i + j] != pattern[j] { + i += 1; + continue 'outer; + } + j += 1; + } + return true; + } + false +} + +// EMIT_MIR gvn_const_eval_polymorphic.optimize_true.GVN.diff +fn optimize_true() -> bool { + // CHECK-LABEL: fn optimize_true( + // CHECK: _0 = const true; + // CHECK-NEXT: return; + (const { type_name_contains_i32(&generic::) }) == const { true } +} + +// EMIT_MIR gvn_const_eval_polymorphic.optimize_false.GVN.diff +fn optimize_false() -> bool { + // CHECK-LABEL: fn optimize_false( + // CHECK: _0 = const false; + // CHECK-NEXT: return; + (const { type_name_contains_i32(&generic::) }) == const { true } +} + +// EMIT_MIR gvn_const_eval_polymorphic.no_optimize.GVN.diff +fn no_optimize() -> bool { + // CHECK-LABEL: fn no_optimize( + // CHECK: _0 = Eq(const no_optimize::::{constant#0}, const no_optimize::::{constant#1}); + // CHECK-NEXT: return; + (const { type_name_contains_i32(&generic::) }) == const { true } +} diff --git a/tests/mir-opt/gvn_type_id_polymorphic.cursed_is_i32.GVN.diff b/tests/mir-opt/gvn_type_id_polymorphic.cursed_is_i32.GVN.diff deleted file mode 100644 index 2f83f54d2afdb..0000000000000 --- a/tests/mir-opt/gvn_type_id_polymorphic.cursed_is_i32.GVN.diff +++ /dev/null @@ -1,12 +0,0 @@ -- // MIR for `cursed_is_i32` before GVN -+ // MIR for `cursed_is_i32` after GVN - - fn cursed_is_i32() -> bool { - let mut _0: bool; - - bb0: { - _0 = Eq(const cursed_is_i32::::{constant#0}, const cursed_is_i32::::{constant#1}); - return; - } - } - diff --git a/tests/mir-opt/gvn_type_id_polymorphic.rs b/tests/mir-opt/gvn_type_id_polymorphic.rs deleted file mode 100644 index 39bc5c24ecc68..0000000000000 --- a/tests/mir-opt/gvn_type_id_polymorphic.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ test-mir-pass: GVN -//@ compile-flags: -C opt-level=2 - -#![feature(core_intrinsics)] - -fn generic() {} - -const fn type_id_of_val(_: &T) -> u128 { - std::intrinsics::type_id::() -} - -// EMIT_MIR gvn_type_id_polymorphic.cursed_is_i32.GVN.diff -fn cursed_is_i32() -> bool { - // CHECK-LABEL: fn cursed_is_i32( - // CHECK: _0 = Eq(const cursed_is_i32::::{constant#0}, const cursed_is_i32::::{constant#1}); - // CHECK-NEXT: return; - (const { type_id_of_val(&generic::) } == const { type_id_of_val(&generic::) }) -} - -fn main() { - dbg!(cursed_is_i32::()); -} From 027126ce0b682367dc796c2cdcf844e162fca496 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Thu, 3 Jul 2025 09:10:49 +0200 Subject: [PATCH 09/10] Port `#[non_exhaustive]` to the new attribute parsing infrastructure --- .../src/attributes.rs | 3 +++ .../src/encode_cross_crate.rs | 1 + .../rustc_attr_parsing/src/attributes/mod.rs | 1 + .../src/attributes/non_exhaustive.rs | 13 ++++++++++ compiler/rustc_attr_parsing/src/context.rs | 2 ++ compiler/rustc_hir_analysis/src/collect.rs | 8 ++++--- compiler/rustc_middle/src/ty/adt.rs | 5 +++- compiler/rustc_parse/src/validate_attr.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 16 ++++++------- compiler/rustc_resolve/src/diagnostics.rs | 6 ++--- src/librustdoc/clean/types.rs | 4 +++- .../clippy_lints/src/exhaustive_items.rs | 6 +++-- .../clippy_lints/src/manual_non_exhaustive.rs | 13 +++++----- src/tools/clippy/clippy_utils/src/attrs.rs | 9 +++---- tests/ui/attributes/malformed-attrs.stderr | 15 +++++++----- .../lint/unused/unused-attr-duplicate.stderr | 24 +++++++++---------- .../invalid-attribute.stderr | 10 +++++--- 17 files changed, 88 insertions(+), 49 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 3b5e06c2a88fc..b5934f4e36e89 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -284,6 +284,9 @@ pub enum AttributeKind { /// Represents `#[no_mangle]` NoMangle(Span), + /// Represents `#[non_exhaustive]` + NonExhaustive(Span), + /// Represents `#[optimize(size|speed)]` Optimize(OptimizeAttr, Span), diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs index 145cfba8e424b..02e95ddcb6fdb 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -36,6 +36,7 @@ impl AttributeKind { Naked(..) => No, NoImplicitPrelude(..) => No, NoMangle(..) => No, + NonExhaustive(..) => Yes, Optimize(..) => No, PassByValue(..) => Yes, PubTransparent(..) => Yes, diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 0898b44863a3d..f5ac3890a46a7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -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; diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs new file mode 100644 index 0000000000000..94f6a65c74ecd --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -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 NoArgsAttributeParser for NonExhaustiveParser { + const PATH: &[Symbol] = &[sym::non_exhaustive]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const CREATE: fn(Span) -> AttributeKind = AttributeKind::NonExhaustive; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 5ddb686a8c09c..265e1bb6a8cba 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -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, @@ -144,6 +145,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index aad9b08b2a3a5..271104c20c62b 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -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(..)) + }), ) } diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 6d5a3abf665b9..44165b06f1c33 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -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; @@ -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; } diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 47249b38df5f2..27355a422d1fe 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -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 diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c0ef81166ea0a..c5ced4064140e 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -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), @@ -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( @@ -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>, @@ -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, }); } @@ -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 }); } } } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 18078b760c3e7..c99bc747fd21d 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -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::*; @@ -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); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index cc8f4bbb42cc2..de920469fdca6 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -621,7 +621,7 @@ impl Item { } pub(crate) fn is_non_exhaustive(&self) -> bool { - self.attrs.other_attrs.iter().any(|a| a.has_name(sym::non_exhaustive)) + find_attr!(&self.attrs.other_attrs, AttributeKind::NonExhaustive(..)) } /// Returns a documentation-level item type from the item. @@ -776,6 +776,8 @@ impl Item { } else if let hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) = attr { Some(format!("#[export_name = \"{name}\"]")) + } else if let hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) = attr { + Some("#[non_exhaustive]".to_string()) } else if is_json { match attr { // rustdoc-json stores this in `Item::deprecation`, so we diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs index 86d9038ec45d3..7dda3e0fdb91c 100644 --- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs +++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs @@ -4,7 +4,9 @@ use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::sym; +use rustc_attr_data_structures::AttributeKind; +use rustc_attr_data_structures::find_attr; + declare_clippy_lint! { /// ### What it does @@ -85,7 +87,7 @@ impl LateLintPass<'_> for ExhaustiveItems { }; if cx.effective_visibilities.is_exported(item.owner_id.def_id) && let attrs = cx.tcx.hir_attrs(item.hir_id()) - && !attrs.iter().any(|a| a.has_name(sym::non_exhaustive)) + && !find_attr!(attrs, AttributeKind::NonExhaustive(..)) && fields.iter().all(|f| cx.tcx.visibility(f.def_id).is_public()) { span_lint_and_then(cx, lint, item.span, msg, |diag| { diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index 3562b1ff5ccec..51696b388800f 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -4,7 +4,6 @@ use clippy_utils::is_doc_hidden; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_indent; use itertools::Itertools; -use rustc_ast::attr; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; @@ -12,7 +11,9 @@ use rustc_hir::{Expr, ExprKind, Item, ItemKind, QPath, TyKind, VariantData}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{Span, sym}; +use rustc_span::Span; +use rustc_attr_data_structures::find_attr; +use rustc_attr_data_structures::AttributeKind; declare_clippy_lint! { /// ### What it does @@ -93,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive { .then_some((v.def_id, v.span)) }); if let Ok((id, span)) = iter.exactly_one() - && !attr::contains_name(cx.tcx.hir_attrs(item.hir_id()), sym::non_exhaustive) + && !find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::NonExhaustive(..)) { self.potential_enums.push((item.owner_id.def_id, id, item.span, span)); } @@ -113,10 +114,10 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive { item.span, "this seems like a manual implementation of the non-exhaustive pattern", |diag| { - if let Some(non_exhaustive) = - attr::find_by_name(cx.tcx.hir_attrs(item.hir_id()), sym::non_exhaustive) + if let Some(non_exhaustive_span) = + find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::NonExhaustive(span) => *span) { - diag.span_note(non_exhaustive.span(), "the struct is already non-exhaustive"); + diag.span_note(non_exhaustive_span, "the struct is already non-exhaustive"); } else { let indent = snippet_indent(cx, item.span).unwrap_or_default(); diag.span_suggestion_verbose( diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs index 8a0ff5323c98d..4c7a589e185b9 100644 --- a/src/tools/clippy/clippy_utils/src/attrs.rs +++ b/src/tools/clippy/clippy_utils/src/attrs.rs @@ -7,9 +7,10 @@ use rustc_middle::ty::{AdtDef, TyCtxt}; use rustc_session::Session; use rustc_span::{Span, Symbol}; use std::str::FromStr; - +use rustc_attr_data_structures::find_attr; use crate::source::SpanRangeExt; use crate::{sym, tokenize_with_text}; +use rustc_attr_data_structures::AttributeKind; /// Deprecation status of attributes known by Clippy. pub enum DeprecationStatus { @@ -165,13 +166,13 @@ pub fn is_doc_hidden(attrs: &[impl AttributeExt]) -> bool { pub fn has_non_exhaustive_attr(tcx: TyCtxt<'_>, adt: AdtDef<'_>) -> bool { adt.is_variant_list_non_exhaustive() - || tcx.has_attr(adt.did(), sym::non_exhaustive) + || find_attr!(tcx.get_all_attrs(adt.did()), AttributeKind::NonExhaustive(..)) || adt.variants().iter().any(|variant_def| { - variant_def.is_field_list_non_exhaustive() || tcx.has_attr(variant_def.def_id, sym::non_exhaustive) + variant_def.is_field_list_non_exhaustive() || find_attr!(tcx.get_all_attrs(variant_def.def_id), AttributeKind::NonExhaustive(..)) }) || adt .all_fields() - .any(|field_def| tcx.has_attr(field_def.did, sym::non_exhaustive)) + .any(|field_def| find_attr!(tcx.get_all_attrs(field_def.did), AttributeKind::NonExhaustive(..))) } /// Checks if the given span contains a `#[cfg(..)]` attribute diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index bdebe155aba0a..32b0ddf87ba4f 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -206,12 +206,6 @@ error: malformed `automatically_derived` attribute input LL | #[automatically_derived = 18] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[automatically_derived]` -error: malformed `non_exhaustive` attribute input - --> $DIR/malformed-attrs.rs:196:1 - | -LL | #[non_exhaustive = 1] - | ^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[non_exhaustive]` - error: malformed `thread_local` attribute input --> $DIR/malformed-attrs.rs:202:1 | @@ -552,6 +546,15 @@ LL | #[rustc_layout_scalar_valid_range_end] | expected this to be a list | help: must be of the form: `#[rustc_layout_scalar_valid_range_end(end)]` +error[E0565]: malformed `non_exhaustive` attribute input + --> $DIR/malformed-attrs.rs:196:1 + | +LL | #[non_exhaustive = 1] + | ^^^^^^^^^^^^^^^^^---^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[non_exhaustive]` + error: attribute should be applied to `const fn` --> $DIR/malformed-attrs.rs:34:1 | diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index d9ceca2f29bd0..eff478d04aee8 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -65,18 +65,6 @@ LL | #[should_panic] | ^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -error: unused attribute - --> $DIR/unused-attr-duplicate.rs:66:1 - | -LL | #[non_exhaustive] - | ^^^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:65:1 - | -LL | #[non_exhaustive] - | ^^^^^^^^^^^^^^^^^ - error: unused attribute --> $DIR/unused-attr-duplicate.rs:70:1 | @@ -190,6 +178,18 @@ LL | #[must_use] | ^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +error: unused attribute + --> $DIR/unused-attr-duplicate.rs:66:1 + | +LL | #[non_exhaustive] + | ^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/unused-attr-duplicate.rs:65:1 + | +LL | #[non_exhaustive] + | ^^^^^^^^^^^^^^^^^ + error: unused attribute --> $DIR/unused-attr-duplicate.rs:74:1 | diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.stderr index 136cd763b05c1..1ac017aa08b9d 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.stderr @@ -1,8 +1,11 @@ -error: malformed `non_exhaustive` attribute input +error[E0565]: malformed `non_exhaustive` attribute input --> $DIR/invalid-attribute.rs:1:1 | LL | #[non_exhaustive(anything)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[non_exhaustive]` + | ^^^^^^^^^^^^^^^^----------^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[non_exhaustive]` error[E0701]: attribute should be applied to a struct or enum --> $DIR/invalid-attribute.rs:5:1 @@ -27,4 +30,5 @@ LL | | } error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0701`. +Some errors have detailed explanations: E0565, E0701. +For more information about an error, try `rustc --explain E0565`. From 626521d6939e9cd1cf4ad13bf1e926854cff88e9 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Tue, 1 Jul 2025 02:46:47 +0500 Subject: [PATCH 10/10] cleaned up some tests --- .../ui/codegen/output-slot-init-vs-noninit.rs | 54 +++++++++++-------- tests/ui/codegen/remark-flag-functionality.rs | 14 ++--- .../codegen/shift-right-operand-mutation.rs | 18 ++++--- tests/ui/codegen/sret-aliasing-rules.rs | 13 +++-- .../ui/macros/macro-paren-span-diagnostic.rs | 6 ++- .../macros/macro-paren-span-diagnostic.stderr | 2 +- .../panics/panic-during-display-formatting.rs | 12 +++-- tests/ui/panics/panic-handler-closures.rs | 6 ++- .../ui/parser/ufcs-return-unused-parens.fixed | 9 ++-- tests/ui/parser/ufcs-return-unused-parens.rs | 9 ++-- .../parser/ufcs-return-unused-parens.stderr | 4 +- .../partialeq-ref-mismatch-diagnostic.rs | 4 +- .../partialeq-ref-mismatch-diagnostic.stderr | 8 +-- 13 files changed, 99 insertions(+), 60 deletions(-) diff --git a/tests/ui/codegen/output-slot-init-vs-noninit.rs b/tests/ui/codegen/output-slot-init-vs-noninit.rs index 97757e74fc4ea..55586843740a7 100644 --- a/tests/ui/codegen/output-slot-init-vs-noninit.rs +++ b/tests/ui/codegen/output-slot-init-vs-noninit.rs @@ -1,26 +1,48 @@ +//! Check that output slots work correctly for both initializing and non-initializing assignments. +//! +//! Regression test for . + //@ run-pass #![allow(dead_code)] #![allow(unused_assignments)] #![allow(unknown_lints)] - #![allow(dead_assignment)] #![allow(unused_variables)] -struct A { a: isize, b: isize } -struct Abox { a: Box, b: Box } +struct A { + a: isize, + b: isize, +} -fn ret_int_i() -> isize { 10 } +struct Abox { + a: Box, + b: Box, +} -fn ret_ext_i() -> Box { Box::new(10) } +fn ret_int_i() -> isize { + 10 +} -fn ret_int_rec() -> A { A {a: 10, b: 10} } +fn ret_ext_i() -> Box { + Box::new(10) +} -fn ret_ext_rec() -> Box { Box::new(A {a: 10, b: 10}) } +fn ret_int_rec() -> A { + A { a: 10, b: 10 } +} -fn ret_ext_mem() -> Abox { Abox {a: Box::new(10), b: Box::new(10) } } +fn ret_ext_rec() -> Box { + Box::new(A { a: 10, b: 10 }) +} + +fn ret_ext_mem() -> Abox { + Abox { a: Box::new(10), b: Box::new(10) } +} -fn ret_ext_ext_mem() -> Box { Box::new(Abox{a: Box::new(10), b: Box::new(10) }) } +fn ret_ext_ext_mem() -> Box { + Box::new(Abox { a: Box::new(10), b: Box::new(10) }) +} pub fn main() { let mut int_i: isize; @@ -29,40 +51,28 @@ pub fn main() { let mut ext_rec: Box; let mut ext_mem: Abox; let mut ext_ext_mem: Box; - int_i = ret_int_i(); // initializing + int_i = ret_int_i(); // initializing int_i = ret_int_i(); // non-initializing - int_i = ret_int_i(); // non-initializing ext_i = ret_ext_i(); // initializing - ext_i = ret_ext_i(); // non-initializing - ext_i = ret_ext_i(); // non-initializing int_rec = ret_int_rec(); // initializing - int_rec = ret_int_rec(); // non-initializing - int_rec = ret_int_rec(); // non-initializing ext_rec = ret_ext_rec(); // initializing - ext_rec = ret_ext_rec(); // non-initializing - ext_rec = ret_ext_rec(); // non-initializing ext_mem = ret_ext_mem(); // initializing - ext_mem = ret_ext_mem(); // non-initializing - ext_mem = ret_ext_mem(); // non-initializing ext_ext_mem = ret_ext_ext_mem(); // initializing - ext_ext_mem = ret_ext_ext_mem(); // non-initializing - ext_ext_mem = ret_ext_ext_mem(); // non-initializing - } diff --git a/tests/ui/codegen/remark-flag-functionality.rs b/tests/ui/codegen/remark-flag-functionality.rs index 165fc63c0076a..797c55ba830c1 100644 --- a/tests/ui/codegen/remark-flag-functionality.rs +++ b/tests/ui/codegen/remark-flag-functionality.rs @@ -1,24 +1,26 @@ +//! Check that `-Cremark` flag correctly emits LLVM optimization remarks. +//! +//! Regression test for . + //@ build-pass //@ ignore-pass //@ revisions: all inline merge1 merge2 //@ compile-flags: --crate-type=lib -Cdebuginfo=1 -Copt-level=2 -// + // Check that remarks can be enabled individually or with "all": -// //@ [all] compile-flags: -Cremark=all //@ [inline] compile-flags: -Cremark=inline -// + // Check that values of -Cremark flag are accumulated: -// //@ [merge1] compile-flags: -Cremark=all -Cremark=giraffe //@ [merge2] compile-flags: -Cremark=inline -Cremark=giraffe + //@ dont-check-compiler-stderr //@ dont-require-annotations: NOTE #[no_mangle] #[inline(never)] -pub fn f() { -} +pub fn f() {} #[no_mangle] pub fn g() { diff --git a/tests/ui/codegen/shift-right-operand-mutation.rs b/tests/ui/codegen/shift-right-operand-mutation.rs index 016a667e93785..187337cecf3c0 100644 --- a/tests/ui/codegen/shift-right-operand-mutation.rs +++ b/tests/ui/codegen/shift-right-operand-mutation.rs @@ -1,12 +1,18 @@ +//! Ensure shift operations don't mutate their right operand. +//! +//! This test checks that expressions like `0 << b` don't accidentally +//! modify the variable `b` due to codegen issues with virtual registers. +//! +//! Regression test for . + //@ run-pass -#![allow(unused_must_use)] -// Regression test for issue #152. pub fn main() { - let mut b: usize = 1_usize; + let mut b: usize = 1; while b < std::mem::size_of::() { - 0_usize << b; - b <<= 1_usize; - println!("{}", b); + // This shift operation should not mutate `b` + let _ = 0_usize << b; + b <<= 1; } + assert_eq!(8, b); } diff --git a/tests/ui/codegen/sret-aliasing-rules.rs b/tests/ui/codegen/sret-aliasing-rules.rs index 0dfaa19fadb0f..f35e722f764a5 100644 --- a/tests/ui/codegen/sret-aliasing-rules.rs +++ b/tests/ui/codegen/sret-aliasing-rules.rs @@ -1,3 +1,11 @@ +//! Check that functions with sret results don't violate aliasing rules. +//! +//! When `foo = func(&mut foo)` is called, the compiler must avoid creating +//! two mutable references to the same variable simultaneously (one for the +//! parameter and one for the hidden sret out-pointer). +//! +//! Regression test for . + //@ run-pass #[derive(Copy, Clone)] @@ -14,10 +22,7 @@ pub fn foo(f: &mut Foo) -> Foo { } pub fn main() { - let mut f = Foo { - f1: 8, - _f2: 9, - }; + let mut f = Foo { f1: 8, _f2: 9 }; f = foo(&mut f); assert_eq!(f.f1, 8); } diff --git a/tests/ui/macros/macro-paren-span-diagnostic.rs b/tests/ui/macros/macro-paren-span-diagnostic.rs index c8cb63d5190d1..cbcb0231e4e30 100644 --- a/tests/ui/macros/macro-paren-span-diagnostic.rs +++ b/tests/ui/macros/macro-paren-span-diagnostic.rs @@ -1,5 +1,6 @@ -// Be smart about span of parenthesized expression in macro. +//! Check that error spans in parenthesized macro expressions point to the call site. +#[rustfmt::skip] macro_rules! paren { ($e:expr) => (($e)) // ^^^^ do not highlight here @@ -7,8 +8,9 @@ macro_rules! paren { mod m { pub struct S { - x: i32 + x: i32, } + pub fn make() -> S { S { x: 0 } } diff --git a/tests/ui/macros/macro-paren-span-diagnostic.stderr b/tests/ui/macros/macro-paren-span-diagnostic.stderr index da2f57033a44e..ede6ff51c7129 100644 --- a/tests/ui/macros/macro-paren-span-diagnostic.stderr +++ b/tests/ui/macros/macro-paren-span-diagnostic.stderr @@ -1,5 +1,5 @@ error[E0616]: field `x` of struct `S` is private - --> $DIR/paren-span.rs:19:14 + --> $DIR/macro-paren-span-diagnostic.rs:21:14 | LL | paren!(s.x); | ^ private field diff --git a/tests/ui/panics/panic-during-display-formatting.rs b/tests/ui/panics/panic-during-display-formatting.rs index 6505a69fef7cf..a307ee493854a 100644 --- a/tests/ui/panics/panic-during-display-formatting.rs +++ b/tests/ui/panics/panic-during-display-formatting.rs @@ -1,3 +1,5 @@ +//! Check that panics in `Display::fmt` during printing are properly handled. + //@ run-pass //@ needs-unwind @@ -18,8 +20,10 @@ impl Display for A { fn main() { set_output_capture(Some(Arc::new(Mutex::new(Vec::new())))); - assert!(std::panic::catch_unwind(|| { - eprintln!("{}", A); - }) - .is_err()); + assert!( + std::panic::catch_unwind(|| { + eprintln!("{}", A); + }) + .is_err() + ); } diff --git a/tests/ui/panics/panic-handler-closures.rs b/tests/ui/panics/panic-handler-closures.rs index b161859bf9c51..27fea92572050 100644 --- a/tests/ui/panics/panic-handler-closures.rs +++ b/tests/ui/panics/panic-handler-closures.rs @@ -1,10 +1,12 @@ -//@ build-pass (FIXME(62277): could be check-pass?) +//! Check that closures can be used inside `#[panic_handler]` functions. + +//@ check-pass #![crate_type = "rlib"] #![no_std] #[panic_handler] -pub fn panic_fmt(_: &::core::panic::PanicInfo) -> ! { +pub fn panicfmt(_: &::core::panic::PanicInfo) -> ! { |x: u8| x; loop {} } diff --git a/tests/ui/parser/ufcs-return-unused-parens.fixed b/tests/ui/parser/ufcs-return-unused-parens.fixed index 440b22edd7d51..811a853b76933 100644 --- a/tests/ui/parser/ufcs-return-unused-parens.fixed +++ b/tests/ui/parser/ufcs-return-unused-parens.fixed @@ -1,13 +1,16 @@ +//! Check that UFCS syntax works correctly in return statements +//! without requiring workaround parentheses. +//! +//! Regression test for . + //@ run-pass //@ run-rustfix #![allow(dead_code)] #![warn(unused_parens)] -// Parser test for #37765 - fn with_parens(arg: T) -> String { - return ::to_string(&arg); //~WARN unnecessary parentheses around `return` value + return ::to_string(&arg); //~ WARN unnecessary parentheses around `return` value } fn no_parens(arg: T) -> String { diff --git a/tests/ui/parser/ufcs-return-unused-parens.rs b/tests/ui/parser/ufcs-return-unused-parens.rs index 7eaacd6bba78b..6ea69ef9a2627 100644 --- a/tests/ui/parser/ufcs-return-unused-parens.rs +++ b/tests/ui/parser/ufcs-return-unused-parens.rs @@ -1,13 +1,16 @@ +//! Check that UFCS syntax works correctly in return statements +//! without requiring workaround parentheses. +//! +//! Regression test for . + //@ run-pass //@ run-rustfix #![allow(dead_code)] #![warn(unused_parens)] -// Parser test for #37765 - fn with_parens(arg: T) -> String { - return (::to_string(&arg)); //~WARN unnecessary parentheses around `return` value + return (::to_string(&arg)); //~ WARN unnecessary parentheses around `return` value } fn no_parens(arg: T) -> String { diff --git a/tests/ui/parser/ufcs-return-unused-parens.stderr b/tests/ui/parser/ufcs-return-unused-parens.stderr index 2cc786fd947c2..6c09e98e7b105 100644 --- a/tests/ui/parser/ufcs-return-unused-parens.stderr +++ b/tests/ui/parser/ufcs-return-unused-parens.stderr @@ -1,11 +1,11 @@ warning: unnecessary parentheses around `return` value - --> $DIR/path-lookahead.rs:10:12 + --> $DIR/ufcs-return-unused-parens.rs:13:12 | LL | return (::to_string(&arg)); | ^ ^ | note: the lint level is defined here - --> $DIR/path-lookahead.rs:5:9 + --> $DIR/ufcs-return-unused-parens.rs:10:9 | LL | #![warn(unused_parens)] | ^^^^^^^^^^^^^ diff --git a/tests/ui/traits/partialeq-ref-mismatch-diagnostic.rs b/tests/ui/traits/partialeq-ref-mismatch-diagnostic.rs index 34b88b8a86685..26ef8050b8769 100644 --- a/tests/ui/traits/partialeq-ref-mismatch-diagnostic.rs +++ b/tests/ui/traits/partialeq-ref-mismatch-diagnostic.rs @@ -1,8 +1,10 @@ +//! Check diagnostic messages for `PartialEq` trait bound mismatches between `&T` and `T`. + fn foo(a: &T, b: T) { a == b; //~ ERROR E0277 } -fn foo2(a: &T, b: T) where { +fn foo2(a: &T, b: T) { a == b; //~ ERROR E0277 } diff --git a/tests/ui/traits/partialeq-ref-mismatch-diagnostic.stderr b/tests/ui/traits/partialeq-ref-mismatch-diagnostic.stderr index f5de1308e8714..4cbd31656dc53 100644 --- a/tests/ui/traits/partialeq-ref-mismatch-diagnostic.stderr +++ b/tests/ui/traits/partialeq-ref-mismatch-diagnostic.stderr @@ -1,5 +1,5 @@ error[E0277]: can't compare `&T` with `T` - --> $DIR/partialeq_help.rs:2:7 + --> $DIR/partialeq-ref-mismatch-diagnostic.rs:4:7 | LL | a == b; | ^^ no implementation for `&T == T` @@ -15,7 +15,7 @@ LL | fn foo(a: &T, b: T) where &T: PartialEq { | ++++++++++++++++++++++ error[E0277]: can't compare `&T` with `T` - --> $DIR/partialeq_help.rs:6:7 + --> $DIR/partialeq-ref-mismatch-diagnostic.rs:8:7 | LL | a == b; | ^^ no implementation for `&T == T` @@ -25,10 +25,10 @@ help: consider dereferencing here | LL | *a == b; | + -help: consider extending the `where` clause, but there might be an alternative better way to express this requirement +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement | LL | fn foo2(a: &T, b: T) where &T: PartialEq { - | ++++++++++++++++ + | ++++++++++++++++++++++ error: aborting due to 2 previous errors